Come accedere agli oggetti `window` (Pagina di destinazione) quando i valori di @grant sono impostati?

Diciamo che sto lavorando con la seguente pagina web:

  click me  var hello = function() { alert('hello'); } document.getElementById('click').addEventListener('click', function(e) { hello(); });    

e il mio script Greasemonkey è:

 // ==UserScript== // @name My Script // @include http://example.com/hello.html // @version 1 // @grant none // ==/UserScript== window.hello = function() { alert('goodbye'); } 

Con lo script Greasemonkey disabilitato, facendo clic sull’elemento #click sulla pagina viene visualizzato l’avviso “ciao”. Con lo script abilitato, facendo clic sull’elemento viene visualizzato l’avviso ‘addio’.

Abbastanza semplice La funzione hello dalla pagina web viene sostituita dalla funzione nello script Greasemonkey.

Ora diciamo che voglio usare un’API Greasemonkey. Quando ho impostato il valore @grant su un valore valido diverso da ‘none’ (ad esempio // @grant GM_setClipboard ) [che fa sì che Greasemonkey esegua lo script come uno “script di contenuto”, piuttosto che nello scope della pagina come con “none” ], lo script Greasemonkey non funziona.

window.hello non ha più come target l’object corretto nella pagina.

Sostituire window.hello con unsafeWindow.hello sembra funzionare, ma al suo posto viene generato il seguente errore nella console JS:

Errore: authorization negata per accedere all’object

Come posso riscrivere lo script Greasemonkey mentre @grant GM_setClipboard impostato su target e sostituire la funzione hello originale sulla pagina?

Informazioni di sistema:

  • Windows 7 a 64 bit
  • Firefox 32.0
  • Greasemonkey 2.2

Quando si imposta un valore @grant diverso da none, Greasemonkey triggers la sua sandbox e Greasemonkey 2.0 modifica radicalmente la gestione di unsafeWindow .

Ora, per creare o sovrascrivere le variabili nell’objective della pagina di destinazione, è necessario scegliere correttamente da un menu di tecniche. PER ESEMPIO:

Leggere:

  • Una variabile semplice:

     Target page sets: var foo = "bar"; GM script can read: unsafeWindow.foo //-- "bar" 
  • Un object semplice:

     Target page sets: var obj = {A: 1}; GM script can read: unsafeWindow.obj //-- Object { A: 1 } 
  • Un object complesso: questo non è sempre ansible.

Chiamare:

  • Una semplice funzione:

     Target page sets: function func () {console.log ('Hi');} GM script can call: unsafeWindow.func() //-- "Hi" 
  • Una funzione complessa: questo non è sempre ansible.

Scrivere / impostare:

  • Una variabile semplice:

     unsafeWindow.foo = "Apple"; 
  • Un object semplice:

     var gmObject = {X: "123"}; unsafeWindow.obj = cloneInto (gmObject, unsafeWindow); 
  • Una semplice funzione:

     function gmFunc () { console.log ("Lorem ipsum"); //-- Can use GM_ functions in here! :) } unsafeWindow.func = exportFunction (gmFunc, unsafeWindow); 

Considera questo HTML:

  

E questa javascript:

 var simpleGlobalVar = "A simple, global var in the page scope."; var globalObject = {Letter: "A", Number: 2}; function simpleFunction () { console.log ("The target page's simpleFunction was called."); } var sayHello = function() { console.log ('Hello.'); } document.getElementById ('helloBtn').addEventListener ('click', function () { sayHello (); } ); 

che puoi vedere dal vivo in questa pagina jsFiddle .

Se installi ed esegui questo script Greasemonkey su quella pagina:

 // ==UserScript== // @name _Demonstrate accessing target-page variables with @grant values set // @include http://fiddle.jshell.net/sepwL7n6/*/show/ // @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js // @grant GM_addStyle // ==/UserScript== console.log ("*** Greasemonkey script start."); $("body").append ('
Added by Greasemonkey:

'); $("#gmArea > p:first").append (''); $("#gmArea > p:first").append (''); $("#gmShow").click ( function () { //-- Access things from the target-page scope: console.log ("----------------"); console.log ("==> simpleGlobalVar is: ", unsafeWindow.simpleGlobalVar); console.log ("==> globalObject is: ", unsafeWindow.globalObject); console.log ("==> Calling target's simpleFunction():"); unsafeWindow.simpleFunction (); //-- WARNING! This next technique is not robust, but works in some cases. console.log ("==> Calling target's button's click()."); unsafeWindow.document.getElementById ('helloBtn').click (); } ); $("#gmChange").click ( function () { this.disabled = true; //-- Can only click once. unsafeWindow.simpleGlobalVar = "Simple var... Intercepted by GM!"; unsafeWindow.globalObject = cloneInto (gmObject, unsafeWindow); unsafeWindow.sayHello = exportFunction (sayHello, unsafeWindow); console.log ("==> Target page objects were changed."); } ); var gmMessageStr = "Function... Intercepted by GM, but also can use GM_ functions!"; function sayHello () { sayHello.K = (sayHello.K || 0) + 1; console.log (gmMessageStr); GM_addStyle ('body {background: ' + (sayHello.K % 2 ? "lime" : "white") + ';}'); } var gmObject = {message: "Object overridden by GM."};

Apri la console e premi i pulsanti e vedrai che lo script GM è in grado di leggere e modificare le variabili e le funzioni della pagina.


Gli appunti:

  1. Questo è tutto specifico per Firefox .
  2. Per il codice cross platform, e per alcune situazioni complesse, è ansible utilizzare invece Script Injection . Ma il codice iniettato non può accedere direttamente alle funzioni GM_ .
  3. Nota che queste tecniche funzionano solo con variabili javascript e funzioni globali.