XPCNativeWrapper

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 :

  1. son parent (propriété __parent__ en JavaScript) est un objet sécurisé.
  2. il est l'objet de visibilité racine d'un composant JavaScript.
  3. 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 :

  1. 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>).
  2. Son parent est sécurisé, et une de ces trois options est valable :
    1. Elle n'est pas chargée dans un <xul:iframe> ou <xul:browser>.
    2. Elle est chargée dans un <xul:iframe> ou <xul:browser> ne possédant pas d'attribut « type ».
    3. 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- ».

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 :

  1. 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.
  2. 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 :

  1. L'assignation ou la lecture d'une propriété on* sur un XPCNativeWrapper d'un noeud DOM ou d'un objet Window va générer une exception. (Utilisez plutôt addEventListener, et utilisez "event.preventDefault();" dans votre gestionnaire si vous utilisiez "return false;" auparavant.)
  2. L'accès aux cadres par le nom de la fenêtre (par ex window.frameName) ne fonctionne pas sur un XPCNativeWrapper.
  3. document.all ne fonctionne pas avec le XPCNativeWrapper d'un document.
  4. 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 que docWrapper est l'emballage du document HTML doc, alors doc.foo sera un HTMLFormElement tandis que docWrapper.foo sera undefined. Vous pouvez utiliser à la place docWrapper.forms.namedItem("foo") dans votre code.
  5. L'accès aux noeuds par leurs id ne fonctionne pas sur le XPCNativeWrapper d'un document HTML. getElementById doit être utilisé à la place.
  6. 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").
  7. L'accès aux éléments par leurs noms ne fonctionne pas sur le XPCNativeWrapper d'un HTMLCollection. Il est nécessaire d'utiliser la méthode namedItem(). Notez que namedItem renvoie uniquement le premier élément input de ce nom, même s'il en existe plusieurs (par exemple pour des boutons radio) au sein du formulaire.
  8. L'appel de méthodes implémentées par des plugins NPAPI à travers le XPCNativeWrapper pour le nœud correspondant ne fonctionne pas.
  9. 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.
  10. 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.
  11. 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.
  12. 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.
  13. Object.prototype ne correspond pas à la chaîne de prototype d'un XPCNativeWrapper. Comme résultat, plusieurs propriétés Objet.prototype sont indéfinies sur un XPCNativeWrapper (pour être précis, ce sont __proto__, __parent__, __count__, toSource, toLocaleString, valueOf, watch, unwatch, hasOwnProperty, isPrototypeOf, propertyIsEnumerable, __defineGetter__, __defineSetter__, __lookupGetter__, et __lookupSetter__).
  14. La méthode importXPCNative que l'ancienne implémentation XPCNativeWrapper utilisait n'est plus gérée.
  15. 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 fonction eval 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).


Étiquettes et contributeurs liés au document

Contributeurs à cette page : Mgjbot, BenoitL, VincentN, Sébastien, Chbok
Dernière mise à jour par : Mgjbot,