XPCNativeWrapper
è un modo di imballare un oggetto in modo da rendere sicuro l'accesso tramite un codice privilegiato. Può essere utilizzato in tutte le versioni di Firefox, anche se il comportamento è in qualche modo cambiato a partire da Firefox 1.5 (Gecko 1.8). Guarda la voce XPCNativeWrapper
su MozillaZine(EN) per il comportamento di XPCNativeWrapper
nelle versioni di Firefox precedenti alla 1.5. Questo articolo tratta XPCNativeWrapper
solo su Firefox 1.5 o superiori.
Che cosa fa XPCNativeWrapper
Un XPCNativeWrapper
limita l'accesso alle proprietà e ai metodi dell'oggetto che imballa. Le sole proprietà e metodi accessibili attraverso un XPCNativeWrapper
sono quelle definite nell'IDL oppure quelle definite da un livello DOM pari a 0 (anche se alcune proprietà o metodi di livello zero non funzionano con un XPCNativeWrapper
). In particolare, le proprietà aggiunte ad un oggetto con un JavaScript non sono esposte ad un XPCNativeWrapper
per l'oggetto imballato, e l'accesso e la modifica non sono definibili con __defineGetter__
e __defineSetter__
. L'intento è quello di permettere un accesso sicuro ai metodi definiti dall'IDL dell'oggetto.
Tipi di XPCNativeWrapper
Esistono tre diversi tipi di XPCNativeWrapper
in Firefox 1.5. Tutti e tre i tipi imballano un ogetto potenzialmente non sicuro e garantiscono un accesso sicuro alle sue proprietà e metodi.
Le differenze di comportamento tra i tre tipi di XPCNativeWrapper
sono determinate dalle due caratteristiche che un XPCNativeWrapper
può avere. Un XPCNativeWrapper
può essere esplicito (o, all'opposto, implicito) e può essere profondo (o, al contrario, superficiale). Il tipo di imballaggio è determinato dal modo in cui è stato creato, come segue:
Creato da | Esplicito/Implicito | Profondo/Superficiale |
---|---|---|
Accesso di uno script protetto ad un oggetto non attendibile | Implicito | Profondo |
Chiamata del costruttore con argomento testuale | Esplicito | Superficiale |
Chiamata del costruttore senza argomento testuale | Esplicito | Profondo |
Esplicito vs. Implicito
La differenza di comportamento tra un XPCNativeWrapper
esplicito ed uno implicito è che l'accesso ad una proprietà tramite un XPCNativeWrapper
implicito da parte di uno script non protetto NON è sicuro. L'accesso alla proprietà sarà trasmesso attraverso il wrappedJSObject
del XPCNativeWrapper
.
Questo significa che gli script non protetti non devono preoccuparsi di eventuali bug perché gli altri codici li tratteranno come un XPCNativeWrapper
implicito. Dall'altro lato, tali script hanno bisogno di evitare l'accesso di oggetti non sicuri.
L'accesso ad una proprietà attraverso un XPCNativeWrapper
esplicito è sicuro indipendentemente dalla circostanza che lo script che effettua la chiamata sia protetto o meno.
Profondo vs. Superficiale
La differenza di comportamento tra un XPCNativeWrapper
profondo ed uno superficiale risiede nel fatto che quando si effettua l'accesso ad una proprietà o quando una funzione viene richiamata in un imballaggio profondo, il valore restituito sarà imballata in un suo proprio XPCNativeWrapper
. Il nuovo XPCNativeWrapper
sarà profondo e sarà anche esplicito se e solo se il XPCNativeWrapper
al quale appartiene la proprietà alla quale si è effettuato l'accesso sia anch'esso esplicito. Al contrario, quando una si accede ad una proprietà o ad una funzione mediante un imballaggio superficiale, il valore restituito potrebbe essere un oggetto non sicuro.
Ad esempio, poniamo di avere tre istanze di XPCNativeWrapper
per lo stesso oggetto window
. Chiamiamole deepExplicitWindow
, deepImplicitWindow
e shallowWindow
. Avremo quindi:
var doc1 = deepExplicitWindow.document;
// doc1 è ora un XPCNativeWrapper
profondo ed esplicito
// per l'oggetto del documento. Accedere a doc1.open() è sicuro.
var doc2 = deepImplicitWindow.document;
// Se lo script di chiamata ha impostato xpcnativewrappers=yes, doc2 è un
// XPCNativeWrapper
profondo ed implicito per l'oggetto documento.
// Altrimenti doc2 è un oggetto documento non sicuro, datoché l'accesso
// alle proprietà è passato semplicemente all'oggetto non sicuro.
var doc3 = shallowWindow.document; // doc3 è un oggetto documento non sicuro.
Creare un oggetto XPCNativeWrapper
Ci sono tre modi diversi per creare un oggetto XPCNativeWrapper
; un modo per ognuno dei tre tipi.
Accesso di uno script protetto ad un oggetto non attendibile
Ogni volta che uno script protetto accede ad un oggetto non attendibile otterrà un XPCNativeWrapper
implicito e profondo . L'accesso alle proprietà di questo XPCNativeWrapper
da parte di uno script protetto è sicuro.
Un imballaggio creato in tal modo esisterà a lungo quanto l'oggetto imballato, e un doppio accesso all'oggetto restituirà lo stesso XPCNativeWrapper
.
Che cos'è uno script protetto?
Uno script si considera protetto o non protetto a seconda del suo URI. Uno script si considera protetto solamente se il suo URI inizia con un prefisso protetto conosciuto. I prefissi protetti in Firefox 1.5 sono determinati dal Registro Chrome.
Come opzione predefinita, tutti i pacchetti di contenuti sono protetti. Questo significa che tutti gli URI che iniziano con "<tt>chrome://<package name>/content/</tt>" (per ogni pacchetto) sono protetti. I singoli pacchetti possono sovrascrivere questa regola utilizzando un contrassegno nel file chrome manifest.
Che cos'è un oggetto non attendibile?
Tutti gli oggetti possono essere sia sicuri che non sicuri. Un oggetto è attendibile se una qualsiasi delle seguenti affermazioni è soddisfatta:
- Il suo oggetto genitore è attendibile (la proprietà
__parent__
in JavaScript). - E' un oggeto che definisce il raggio d'azione di un componente JavaScript.
- E' l'oggetto
window
per una finestra attendibile.
Poiché tutti gli oggetti DOM in una finestra hanno l'oggetto window
come __parent__
nella loro catena d'oggetti, sranno attendibili se e solo se anche la loro finestra risulta attendibile.
Che cos'è una finestra attendibile?
Se una finestra sia sicura o meno dipende dal suo contenitore. Una finestra è attendibile se soddisfa una delle seguenti condizioni:
- E' una finestra di livello principale (es.
<xul:window>
,<xul:dialog>
, o un qualche URI passato in linea di comando con l'indicatore <tt>-chrome</tt>). - L'elemento genitore è attendibile e soddisfa una di queste tre opzioni:
- Non viene caricato in un
<xul:iframe>
o<xul:browser>
. - E' caricato in un
<xul:iframe>
o<xul:browser>
senza l'attributo "tipo". - E' caricato in un
<xul:iframe>
o<xul:browser>
e il valore dell'attributo "tipo" non è "content" e non inizia con "content-".
- Non viene caricato in un
Nota che la circostanza che una finestra sia sicura non dipende dall'URI caricato nella finestra. Quindi, ad esempio, le seguenti stringhe creerebbero finestre attendibili qualora utilizzate in documenti le cui finestre siano già sicure:
-
<xul:browser>
-
<xul:browser type="chrome">
-
<xul:browser type="rabid_dog">
-
<xul:iframe type="foofy">
-
<html:iframe>
-
<html:iframe type="content">
I seguenti valori invece non creerebbero finestre attendibili:
-
<xul:browser type="content">
-
<xul:iframe type="content-primary">
N.B. qualsiasi finestra discendente di una finestra non attendibile è automaticamente un elemento non sicuro.
Cosa accade quando uno script accede ad un oggetto?
La tabella riportata sotto descrive cosa accade quando uno script accede ad un oggetto, e come viene coinvolto il "wrapper".
Script | Oggetto | Effetti |
---|---|---|
Protetto | Attendibile | Non viene creato nessun imballaggio, e dunque lo script ha un pieno accesso all'oggetto. |
Protetto | Non attendibile | Viene creato un XPCNativeWrapper implicito e profondo.
|
Non protetto | Attendibile | Non viene creato nessun imballaggio, come nel caso protetto/attendibile. |
Non protetto | Non attendibile | Non viene creato nessun imballaggio, come nel caso protetto/attendibile. |
Chiamata del costruttore del XPCNativeWrapper
con un argomento testuale
Ad esempio:
var contentWinWrapper = new XPCNativeWrapper(content, "document");
Questo crea un XPCNativeWrapper
esplicito e superficiale. Questa sintassi è stata mantenta per la retrocompatibilità. Mentre l'accesso a tutte le proprietà del oggetto contentWinWrapper
è ora sicuro, l'accesso al valore restituito da queste proprietà NON è sicuro (proprio come nelle versioni precedenti a Firefox 1.5), dal momento che il XPCNativeWrapper
è superficiale. Quindi per confrontare il titolo del contenuto del documento con la selezione corrente del contenuto, occorre fare:
var winWrapper = new XPCNativeWrapper(content, "document", "getSelection()"); var docWrapper = new XPCNativeWrapper(winWrapper.document, "title"); return docWrapper.title == winWrapper.getSelection();
proprio come nelle versioni di Firefox precedenti alla 1.5. Nota che l'argomento "getSelection()"
non è strettamente necessario in questo caso; se non si intende utilizzare tale codice con versioni precedenti a Firefox 1.5, può essere rimosso. Un singolo argomento testuale dopo l'imballaggio dell'oggetto è quanto è necessario a Firefox per creare questo tipo di XPCNativeWrapper
.
Chiamata del costruttore del XPCNativeWrapper
senza un argomento testuale
Ad esempio:
var contentWinWrapper = new XPCNativeWrapper(content);
Questo crea un XPCNativeWrapper
esplicito e profondo. L'accesso alle proprietà di questo XPCNativeWrapper
è sicuro, ed anche i valori restituiti saranno imballati in un oggetto XPCNativeWrapper
profondo ed esplicito.
Impostare le proprietà "expando" in un XPCNativeWrapper
E' possibile impostare le proprietà "expando" (che sono proprietà con nomi non corrispondenti a quelli delle proprietà definite dall'IDL) in un oggetto XPCNativeWrapper
. Se ciò viene fatto, il chrome sarà in grado di vedere queste proprietà "expando", ma il contenuto no. Non esiste un modo sicuro per impostare una proprietà "expando" dal chrome e fare in modo che sia poi leggibile dal contenuto.
Durata della vita di un XPCNativeWrapper
Gli oggetti XPCNativeWrapper
espliciti esistono finché vi viene fatto rifierimento. Creare un nuovo XPCNativeWrapper
esplicito per lo stesso oggetto potenzialmente non sicuro, genera un nuovo imballaggio; una cosa da evitare quando si impostano le proprietà "expando"
Gli oggetti XPCNativeWrapper
impliciti hanno la stessa durata degli oggetti che imballano.
Accedere a proprietà non sicure
Se per qualche ragione è necessario accedere ad una proprietà non sicura, questo può essere effettuato attraverso la proprietà wrappedJSObject
dell'imballaggio. Ad esempio, se docWrapper
è l'imballaggio di doc
, allora
docWrapper.wrappedJSObject.prop
è uguale a
doc.prop
Limitazioni a XPCNativeWrapper
Ci sono alcune proprietà comuni e stili di programmazione che non possono essere utilizzati con un XPCNativeWrapper
. In particolare:
- L'assegnazione o la lettura di una proprietà
on*
su unXPCNativeWrapper
di un nodo DOM o di un oggettoWindow
genererà un eccezione. (Occorre usare inveceaddEventListener
, e utilizzare "event.preventDefault();" nel programma di gestione se si è già utilizzato "return false;" prima.) - L'accesso ai frame tramite il nome della finestra (es.
window.frameName
) non funziona con unXPCNativeWrapper
-
document.all
non funziona in unXPCNativeWrapper
per un documento. - L'accesso ad oggetti con un id (nome) tramite l'id non funziona con un
XPCNativeWrapper
per un documento HTML. Per esempio, se si ha<form name="foo">
edocWrapper
è l'imballaggio del documento HTMLdoc
alloradoc.foo
è unHTMLFormElement
mentredocWrapper.foo
èundefined
. Deve essere utilizzatodocWrapper.forms.namedItem("foo")
. - L'accesso ai nodi attraverso l'id non funziona con un
XPCNativeWrapper
per un documento HTML. Dovrebbe essere utilizzatogetElementById
. - L'accesso agli input attraverso il nome non funziona con un
XPCNativeWrapper
per un modulo (form) HTML. Bisogna usareform.elements.namedItem("inputname")
. - L'accesso ad elementi attraverso il nome non funziona con un
XPCNativeWrapper
per unHTMLCollection
. Occorre usare il metodonamedItem()
. Nota chenamedItem
restituisce solo il primo elemento di input con il nome, anche se vi sono elementi multipli (es. bottoni radio) che abbiano lo stesso nome. - I metodi di chiamata implementati dai plug-in NPAPI attraverso il
XPCNativeWrapper
dei nodi corrispondenti non funzionano. - Non è possibile ottenere o impostare proprietà implementate da plug-in NPAPI attraverso il
XPCNativeWrapper
dei nodi corrispondenti. - I metodi di chiamata implementati attraverso XBL binding associati ad un nodo attraverso il
XPCNativeWrapper
di quel nodo, non funzionano. - Non è possibile ottenere o impostare proprietà implementate attraverso XBL binding associati ad un nodo attraverso il
XPCNativeWrapper
di quel nodo. - L'elenco delle proprietà di un
XPCNativeWrapper
attraverso "for (var p in wrapper)
" non cpntiene le proprietà definte dall'IDL. - Object.prototype non appartiene alla catena di prototipi di un
XPCNativeWrapper
. Come risultato, molte proprietàObject.prototype
non sono definite in unXPCNativeWrapper
(per essere precisi queste sono__proto__
,__parent__
,__count__
,toSource
,toLocaleString
,valueOf
,watch
,unwatch
,hasOwnProperty
,isPrototypeOf
,propertyIsEnumerable
,__defineGetter__
,__defineSetter__
,__lookupGetter__
, e__lookupSetter__
). - Non esiste più il supporto per il metodo
importXPCNative
che le vecchie implementazioni diXPCNativeWrapper
erano solite avere. - L'accesso a classi standard (come
Function
) attraverso unXPCNativeWrapper
non avrà effetto. Per creare funzioni e oggetti con una particolare finestra genitore, occorre utilizzare la funzioneeval
di quella finestra.
Evitare insidie comuni in Greasemonkey(EN) contiene una elaborata spiegazione di alcune di queste limitazioni (sebbene nel contesto degli script di Greasemonkey).