XPCNativeWrapper
permet d'emballer un objet pour qu'il soit sur d'y accéder depuis du code privilègié. Il peut être utilisé dans toutes les versions de Firefox, bien que son comportement ait été légèrement modifié depuis Firefox 1.5 (Gecko 1.8). Consultez les informations sur XPCNativeWrapper
dans la base de connaissance de MozillaZine pour connaître le comportement de XPCNativeWrapper
dans les versions de Firefox antérieures à 1.5. Ce document traite de XPCNativeWrapper
dans Firefox 1.5 et postérieurs.
À quoi sert XPCNativeWrapper
Un XPCNativeWrapper
restreint l'accès aux propriétés et méthodes des objets qu'il enveloppe. Les seules propriétés et méthodes accessibles au travers du XPCNativeWrapper
sont celles définies dans les IDL ou définies par le niveau 0 du DOM (bien que certaines propriétés et méthodes du niveau 0 du DOM ne fonctionnent pas sur un XPCNativeWrapper
). En particulier, les propriétés ajoutées à un objet via JavaScript ne sont pas accessibles à travers un XPCNativeWrapper
, pas plus que les accesseurs et mutateurs définis avec __defineGetter__
et __defineSetter__
. L'objectif est de pouvoir accéder en toute sécurité aux méthodes d'un objet définies dans les IDL .
Assurez-vous de lire la section concernant les bugs connus, en particulier si vous écrivez du code destiné à certaines versions de Firefox 1.5.0.x.
Types de XPCNativeWrapper
Il existe trois types différents de XPCNativeWrapper
dans Firefox 1.5. Chacun enveloppe un objet potentiellement non sur et fournit un accès sécurisé à ses propriétés et méthodes.
Les différences de comportement entre ces trois types sont déterminées par deux caractéristiques du XPCNativeWrapper
. Un XPCNativeWrapper
peut être explicite (ou par opposition, implicite) et peut être profond (ou par opposition, superficiel). Le type de l'emballage créé est déterminé par la façon dont il est créé, de la manière suivante :
Créé par | Explicite/Implicite | Profond/Superficiel |
---|---|---|
Un script protégé accédant à un objet non sécurisé | Implicite | Profond |
Appel du constructeur avec des paramètres | Explicite | Superficiel |
Appel du constructeur sans paramètre | Explicite | Profond |
Explicite/Implicite
La différence de comportement entre un XPCNativeWrapper
explicite et un implicite est qu'un accès à une propriété d'un XPCNativeWrapper
implicite depuis un script non protégé N'est PAS sûr. L'accès à la propriété sera transmis à travers l'objet wrappedJSObject
du XPCNativeWrapper
.
Ainsi, les scripts qui ne sont pas protégés n'ont pas à se soucier de bogues dûs au fait qu'un autre bout de code leur passerait un XPCNativeWrapper
implicite. D'un autre côté, de tels scripts doivent se méfier des accès à des objets non sûrs.
Les accès aux propriétés d'un XPCNativeWrapper
explicite sont sûrs, que le script appelant soit ou non protégé.
Profond/Superficiel
La différence de comportement entre un XPCNativeWrapper
profond et un superficiel est que, lors de l'accès à une propriété ou de l'appel d'une fonction sur un profond, la valeur renvoyée sera enveloppée dans son propre XPCNativeWrapper
. Le nouvel XPCNativeWrapper
sera également profond et sera explicite si et seulement si le XPCNativeWrapper
dont la propriété est accédée était explicite. En revanche, l'accès à une propriété ou l'appel d'une fonction sur un emballage superficiel renverra une valeur qui peut être un objet non sûr.
Par exemple, admettons que nous ayons trois instances de XPCNativeWrapper
pour le même objet window
. Appelons les deepExplicitWindow
, deepImplicitWindow
et shallowWindow
. Nous avons alors :
var doc1 = deepExplicitWindow.document;
// doc1 est maintenant un XPCNativeWrapper
profond et explicite
// pour l'objet document. L'accès à doc1.open() est sûr.
var doc2 = deepImplicitWindow.document;
// Si le code appelant est paramétré avec xpcnativewrappers=yes, doc2 est
// un XPCNativeWrapper
profond et implicite pour l'objet document.
// Autrement, doc2 est un objet document non sécurisé, puisque les accès
// aux propriétés sont simplement transmises à un objet non sécurisé.
var doc3 = shallowWindow.document; // doc3 est maintenant un objet document non sécurisé.
Création d'objets XPCNativeWrapper
Il existe trois manières différentes de créer un objet XPCNativeWrapper
; une pour chacun des trois types.
Script protégé accédant à un objet non sécurisé
À chaque fois qu'un script protégé accède à un objet non sécurisé, il obtient en retour un XPCNativeWrapper
implicite et profond. L'accès aux propriétés de ce XPCNativeWrapper
depuis des scripts protégés est sécurisé.
Un emballage créé de cette façon existera aussi longtemps que l'objet emballé, et accéder à cet objet deux fois de suite donnera le même XPCNativeWrapper
.
Qu'est-ce qu'un script protégé ?
Dans les versions de Firefox comprises entre la 1.5 et la 1.5.0.5, un script est protégé ou non selon son URI. Un script est protégé seulement si son URI commence par un préfixe protégé connu ; les scripts qui ne sont pas chargés par une URI (par exemple les composants implémentés en JavaScript) ne sont pas protégés. Les préfixes protégés dans Firefox 1.5 sont déterminés par le registre Chrome.
Par défaut, tous les paquetages de contenu sont protégés. De ce fait, toutes les URI commençant par "<tt>chrome://<nom du paquetage>/content/</tt>" (quel que soit le paquetage) sont protégées. Des paquetages individuels peuvent contourner ce comportement par une option dans leur fichier manifeste chrome.
À partir de Firefox 1.5.0.6, les composants implémentés depuis JavaScript sont des scripts protégés. Par conséquent, un script est protégé s'il est soit chargé depuis une URI débutant par un préfixe protégé, ou est un composant implémenté en JavaScript.
Qu'est-ce qu'un objet non sécurisé ?
Tous les objets sont soit sécurisés, soit non sécurisés. Un objet est sécurisé si une au moins de ces trois conditions est remplie :
- son parent (propriété
__parent__
en JavaScript) est un objet sécurisé. - il est l'objet de visibilité racine d'un composant JavaScript.
- il s'agit de l'objet
window
d'une fenêtre sécurisée.
Puisque tous les objets DOM d'une fenêtre disposent de l'objet window
dans leur chaîne d'objets __parent__
, ils seront sécurisés si et seulement si la fenêtre dans lesquelle ils se trouvent l'est.
Qu'est-ce qu'une fenêtre sécurisée ?
Une fenêtre est sécurisée ou pas suivant son conteneur. Une fenêtre est sécurisée si une des conditions suivantes est remplie :
- Il s'agit d'une fenêtre de premier niveau (comme
<xul:window>
,<xul:dialog>
, ou une URI quelconque passée en ligne de commande avec l'option <tt>-chrome</tt>). - Son parent est sécurisé, et une de ces trois options est valable :
- Elle n'est pas chargée dans un
<xul:iframe>
ou<xul:browser>
. - Elle est chargée dans un
<xul:iframe>
ou<xul:browser>
ne possédant pas d'attribut « type ». - Elle est chargée dans un
<xul:iframe>
ou<xul:browser>
dont la valeur de l'attribut « type » n'est pas « content » ni ne débute par « content- ».
- Elle n'est pas chargée dans un
Notez que le fait qu'une fenêtre soit sécurisée ne dépend pas de l'URI chargée dans la fenêtre. Par conséquent, les exemples suivants créeront des fenêtres sécurisées s'ils sont utilisés à l'intérieur d'un document dont la fenêtre est déjà sécurisée :
-
<xul:browser>
-
<xul:browser type="chrome">
-
<xul:browser type="rabid_dog">
-
<xul:iframe type="foofy">
-
<html:iframe>
-
<html:iframe type="content">
Ce qui suit ne crée pas de fenêtres sécurisées :
-
<xul:browser type="content">
-
<xul:iframe type="content-primary">
Notez de même que toutes les fenêtres filles d'une fenêtre non sécurisée sont automatiquement non sécurisées.
Que se passe-t-il lorsqu'un script accède à un objet ?
Le tableau ci-dessous décrit ce qui se produit lorsqu'un script accède à un objet et comment l'emballage est impliqué.
Script | Objet | Effets |
---|---|---|
Protégé | Sécurisé | Aucun emballage n'est créé et par conséquent le script obtient un accès complet à l'objet. |
Protégé | Sécurisé | Un XPCNativeWrapper implicite et profond est créé.
|
Non protégé | Sécurisé | Aucun emballage n'est créé, exactement comme dans le cas protégé/sécurisé. |
Non protégé | Non sécurisé | Aucun emballage n'est créé, exactement comme dans le cas protégé/sécurisé. |
Appel du constructeur XPCNativeWrapper
avec des paramètres
Par exemple :
var contentWinWrapper = new XPCNativeWrapper(content, "document");
Cette ligne va créer un XPCNativeWrapper
explicite et superficiel. Cette syntaxe a été conservée pour la compatibilité avec les versions antérieures à Firefox 1.5. Bien que toutes les propriétés de l'objet contentWinWrapper
sont sécurisées, les valeurs renvoyées par ces propriétés NE le sont PAS (comme dans les versions antérieures à Firefox 1.5), puisque XPCNativeWrapper
est superficiel. Donc pour comparer le titre du document courant à la sélection de contenu actuelle, il faut procéder ainsi :
var winWrapper = new XPCNativeWrapper(content, "document", "getSelection()"); var docWrapper = new XPCNativeWrapper(winWrapper.document, "title"); return docWrapper.title == winWrapper.getSelection();
de la même manière qu'avec les versions antérieures à Firefox 1.5. Notez que l'argument "getSelection()"
n'est pas strictement nécessaire ici ; si le code n'est pas destiné à être utilisé avec des versions antérieures à Firefox 1.5, il peut être supprimé. Un seul argument après l'objet emballé est nécessaire à Firefox 1.5 pour créer ce type de XPCNativeWrapper
.
Appel du constructeur XPCNativeWrapper
sans paramètre
Par exemple :
var contentWinWrapper = new XPCNativeWrapper(content);
Cette ligne va créer un XPCNativeWrapper
explicite et profond. L'accès aux propriétés de ce XPCNativeWrapper
est sécurisé, et les valeurs renvoyées seront également emballées dans des objets XPCNativeWrapper
explicites et profonds.
Définition de propriétés "expando" sur XPCNativeWrapper
Il est possible de définir des propriétés "expando" (des propriétés dont les noms ne correspondent à aucune propriété IDL) sur des objets XPCNativeWrapper
. En procédant ainsi, le chrome sera capable de voir ces propriétés expando, mais le contenu ne pourra pas. Il n'existe pas de manière sécurisée de définir une propriété expando depuis le chrome et de la rendre accessible depuis le contenu.
Durée de vie d'un XPCNativeWrapper
Les objets XPCNativeWrapper
explicites existent tant qu'ils sont référencés. Créé un nouvel XPCNativeWrapper
explicite pour le même objet potentiellement non sécurisé créera un nouvel emballage ; c'est une chose à surveiller lors de la définition de propriétés "expando".
Les objets XPCNativeWrapper
implicites ont la même durée de vie que les objets qu'ils emballent.
Accès aux propriétés non sécurisées
Si un accès non sécurisé à une propriété est nécessaire pour une raison précise, il suffit d'employer la propriété wrappedJSObject
de l'emballage. Par exemple, si docWrapper
est l'emballage de doc
, alors
docWrapper.wrappedJSObject.prop
est identique à
doc.prop
Bogues connus
Il existe deux bogues de XPCNativeWrapper connus dans les versions 1.5.0.x :
- Le bug 337095 concerne les versions de Firefox de 1.5 à 1.5.0.4 et empêche la création de l'emballage pour des scripts protégés dans certains cas. En particulier, si un script accède à une propriété ou appelle une fonction qui retourne un objet non sécurisé, un emballage est créé. Cependant, si une fonction dans un script protégé est appellée depuis C++ et qu'un objet non sécurisé est passé en tant qu'argument à cette fonction, l'emballage ne sera pas créé. Les fonctions qui souhaitent être appellées de cette manière doivent réaliser leur propre emballage. Ce bogue est résolu dans Firefox 1.5.0.5 et supérieurs.
- Le bug 345991 concerne les versions de Firefox de 1.5 à 1.5.0.5 et empêche les composants écrits en JavaScript d'être des scripts protégés. Ce bogue est résolu dans Firefox 1.5.0.6 et supérieurs.
Limitations de XPCNativeWrapper
Il existe certaines propriétés couramment utilisées et certains styles de programmation qui ne peuvent pas être employés avec XPCNativeWrapper
. En particulier :
- L'assignation ou la lecture d'une propriété
on*
sur unXPCNativeWrapper
d'un noeud DOM ou d'un objet Window va générer une exception. (Utilisez plutôtaddEventListener
, et utilisez"event.preventDefault();"
dans votre gestionnaire si vous utilisiez"return false;"
auparavant.) - L'accès aux cadres par le nom de la fenêtre (par ex
window.frameName
) ne fonctionne pas sur unXPCNativeWrapper
. -
document.all
ne fonctionne pas avec leXPCNativeWrapper
d'un document. - L'accès aux items nommés par leurs noms ne fonctionne pas sur le
XPCNativeWrapper
d'un document HTML. Par exemple, si vous avez<form name="foo">
et quedocWrapper
est l'emballage du document HTMLdoc
, alorsdoc.foo
sera unHTMLFormElement
tandis quedocWrapper.foo
seraundefined
. Vous pouvez utiliser à la placedocWrapper.forms.namedItem("foo")
dans votre code. - L'accès aux noeuds par leurs id ne fonctionne pas sur le
XPCNativeWrapper
d'un document HTML.getElementById
doit être utilisé à la place. - L'accès aux champs de saisie par leurs noms ne fonctionne pas sur le
XPCNativeWrapper
d'un formulaire HTML. Le code requis à la place est le suivant :form.elements.namedItem("inputname")
. - L'accès aux éléments par leurs noms ne fonctionne pas sur le
XPCNativeWrapper
d'unHTMLCollection
. Il est nécessaire d'utiliser la méthodenamedItem()
. Notez quenamedItem
renvoie uniquement le premier élémentinput
de ce nom, même s'il en existe plusieurs (par exemple pour des boutons radio) au sein du formulaire. - L'appel de méthodes implémentées par des plugins NPAPI à travers le
XPCNativeWrapper
pour le nœud correspondant ne fonctionne pas. - La lecture ou l'affectation de propriétés implémentées par des plugins NPAPI à travers le
XPCNativeWrapper
pour le nœud correspondant ne fonctionne pas. - L'appel de méthodes implémentées via des liaisons XBL attachées à un nœud à travers le
XPCNativeWrapper
pour ce ce nœud ne fonctionne pas. - La lecture ou l'affectation de propriétés implémentées via des liaisons XBL à travers le
XPCNativeWrapper
pour le nœud correspondant ne fonctionne pas. - L'énumération des propriétés d'un
XPCNativeWrapper
via "for (var p in wrapper)
" ne permet de récupérer les propriétés définies dans les IDL. - Object.prototype ne correspond pas à la chaîne de prototype d'un
XPCNativeWrapper
. Comme résultat, plusieurs propriétésObjet.prototype
sont indéfinies sur unXPCNativeWrapper
(pour être précis, ce sont__proto__
,__parent__
,__count__
,toSource
,toLocaleString
,valueOf
,watch
,unwatch
,hasOwnProperty
,isPrototypeOf
,propertyIsEnumerable
,__defineGetter__
,__defineSetter__
,__lookupGetter__
, et__lookupSetter__
). - La méthode
importXPCNative
que l'ancienne implémentationXPCNativeWrapper
utilisait n'est plus gérée. - L'accès aux classes standard (comme
Function
) au travers d'un XPCNativeWrapper ne fonctionnera pas. Pour créer des fonctions et objets avec une fenêtre particulière comme parent, utilisez la fonctioneval
de cette fenêtre.
L'article Avoid Common Pitfalls in Greasemonkey propose une explication élaborée de certaines de ces limitations (dans le contexte de scripts Greasemonkey).