从 Greasemonkey 到 Page 访问变量,反之亦然

IT技术 javascript firefox firefox-addon greasemonkey
2021-01-22 15:21:01

我在test.js 中有以下代码,它在 </body> 之前运行:

alert('stovetop');
alert(greasy);

我在test.user.js 中有以下代码

(function () {

    'use strict';
    var greasy = 'greasy variable';
    document.title = 'greasy title';

}());

'stovetop' 收到警报,所以我知道页面 javascript 有效,并document.title获得更改,因此我知道脚本 javascript 有效。但是,在网页上我收到错误消息:

错误:ReferenceError:greasy 未定义源文件:/test.js

我如何从网页访问由 Greasemonkey 设置的变量,反之亦然?

3个回答
  • Greasemonkey 脚本在单独的范围内运行,也可能在沙箱中运行,具体取决于@grant设置

  • 此外,问题代码greasy在函数范围内隔离(如gladoscc 所说)。

  • 最后,默认情况下,test.js将在 Greasemonkey 脚本执行之前触发,因此无论如何它都不会看到任何设置的变量。使用@run-at document-start来解决这个问题。


所以,给定这个test.js,在之前运行</body>

window.targetPages_GlobalVar = 'stovetop';

console.log ("On target page, local global: ", targetPages_GlobalVar);
console.log ("On target page, script global: ", gmScripts_GlobalVar);

然后以下将起作用:

没有沙箱:

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant       none
// ==/UserScript==

//--- For @grant none, could also use window. instead of unsafeWindow.
unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
    console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


使用沙箱,没有函数作用域,unsafeWindow
==>重要更新: Greasemonkey 在 2.0 版中更改了 unsafeWindow 处理,下一个示例脚本将不适用于 GM 2.0 或更高版本其他两种解决方案仍然有效。

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

unsafeWindow.gmScripts_GlobalVar = 'greasy';

console.log ("In GM script, local global: ", unsafeWindow.targetPages_GlobalVar);
console.log ("In GM script, script global: ", unsafeWindow.gmScripts_GlobalVar);

window.addEventListener ("DOMContentLoaded", function() {
    console.log ("In GM script, local global, after ready: ", unsafeWindow.targetPages_GlobalVar);
}, false);


使用沙箱,没有函数作用域,脚本注入

// ==UserScript==
// @name        _Greasemonkey and target page, variable interaction
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @include     http://output.jsbin.com/esikut/*
// @run-at      document-start
// @grant       GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

function GM_main () {
    window.gmScripts_GlobalVar = 'greasy';

    console.log ("In GM script, local global: ", window.targetPages_GlobalVar);
    console.log ("In GM script, script global: ", window.gmScripts_GlobalVar);

    window.addEventListener ("DOMContentLoaded", function() {
        console.log ("In GM script, local global, after ready: ", window.targetPages_GlobalVar);
    }, false);
}

addJS_Node (null, null, GM_main);

function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

笔记:

  1. 您可以针对此页面(output.jsbin.com/esikut/1)测试这些脚本
  2. 没有沙箱,unsafeWindowwindow都是一样的。
  3. 所有这些脚本在控制台上产生相同的输出:

    In GM script, local global: undefined
    In GM script, script global: greasy
    On target page, local global: stovetop
    On target page, script global: greasy
    In GM script, local global, after ready: stovetop
    
  4. 脚本注入代码将在各种除了Firefox浏览器的工作。unsafeWindow目前仅适用于 Firefox+Greasemonkey(或 Scriptish)或 Chrome+Tampermonkey。

顺便一句,wiki.greasespot.net/UnsafeWindow说使用 unsafeWindow 是不安全的,在这种情况下,更安全的替代方法是什么?
2021-03-19 15:21:01
“更安全”的替代@grant none方法是使用该方法但替换unsafeWindowwindow(尽管它们@grant none在生效相同的),或者使用脚本注入方法。... 然而,使用的风险unsafeWindow被大大夸大了——没有报告真正的漏洞利用。只要您不在主动针对 GM 脚本的站点上,就不会有风险。
2021-04-02 15:21:01

您的变量greasy是在匿名函数的范围内定义的。greasy甚至无法在您的用户脚本中访问,除非它是您的功能的一部分。例子:

(function(){
    var foo = 5;
    alert(foo);
}();
alert(foo); //ERROR, because foo is undefined outside of the function.

这样做:

var foo = 5;
(function(){
     alert(foo);
}();
alert(foo);

另外,为什么要将所有代码放在匿名函数中然后执行?

我只是使用了一个greasemonkey 模板脚本,它在匿名函数中有示例代码。我认为它是greasemonkey 脚本所必需的。我将 var 声明移到了函数之外,但仍然无法从页面上的 test.js 脚本中提醒变量值。
2021-03-15 15:21:01
会不会是我的 test.js 脚本在 Greasemonkey 之前运行?如果是这样,我怎样才能延迟它?
2021-03-24 15:21:01

您还可以使用localStorage

localStorage.setItem("numberOfThings", "42");

localStorage.getItem("numberOfThings");