如何在没有“unsafeWindow”的情况下进行编程?

时间:2011-12-12 12:51:45

标签: javascript security greasemonkey

在我的Greasemonkey脚本中,我想覆盖网页中仍然存在的功能。

所以我正在使用这个JavaScript代码:

var oldDoWork = DoWork;

unsafeWindow.DoWork = function()
{
    // Do some new work
    ...

    oldDoWork(); // Call the old function
}

有效。

但该方法存在两个问题:

  1. unsafeWindow功能是一个安全问题,来自Greasemonkey说。
  2. 在此新功能中,我们无法使用GM_getValueGM_setValue。使用计时器的解决方法会导致异步作业的其他一些问题。
  3. 如何在不使用unsafeWindow的情况下管理上述代码?

2 个答案:

答案 0 :(得分:1)

为避免不安全的窗口,您可以使用:

location.assign("javascript:YOUR_CODE_GOES_HERE");

但这不会让你使用GM_ *函数。

使用GM_ *“退出GM范围”的唯一方法是使用计时器。

所以基本上,你的问题的答案是:你是以正确的方式,你只是做不了多少。

如果您的功能没有返回任何内容,我建议您使用location.assign

答案 1 :(得分:0)

如果你想避免unsafeWindow,请将与页面的JS交互的代码注入页面。请参阅下面的addJS_Node()

要在此类活动中触发GM_功能,您能够通过以下方式进行互动:

  • 编写节点并收听DOMSubtreeModified(在W3C规范中已弃用)。但是,a bug in FF/GM prevents this for now

  • 发送自定义事件。再次,GM/FF bugs and features prevent that for now
    请注意,例如,click事件可以在用户实际点击 时调用使用GM_函数 的代码。但是,以编程方式生成相同的点击事件,但失败并显示"Greasemonkey access violation: unsafeWindow cannot call..."错误。

所以,目前,解决方法仍然是使用计时器,如果您愿意,可以避免unsafeWindow

//--- Put everything that goes into the main page, inside myJS().
function myJS () {

    window.oldDoWork = DoWork;

    window.DoWork = function() {
        // Do some new work

        callGM_setValue ("From target page", "some value");

        window.oldDoWork(); // Call the old function
    }

    function callGM_setValue (varName, varValue) {

        //--- Generate and dispatch a synthetic event.
        var zEvent  = document.createEvent ("CustomEvent");
        zEvent.initCustomEvent (
            "messageToGM_setvalue", true, false,
            {Name: varName, Value: varValue}
        );

        document.body.dispatchEvent (zEvent);
    }
}

document.body.addEventListener (
    "messageToGM_setvalue", fireGM_setValue, false
);

function fireGM_setValue (zEvent) {

    /*--- setTimeout remains one of the few things that can cleanse
        the calling tree of it's "unsafe" origins.
    */
    setTimeout (function() {
        GM_setValue (zEvent.detail.Name, zEvent.detail.Value);
    }, 0);
}

addJS_Node (null, null, myJS);

function addJS_Node (text, s_URL, funcToRun) {
    var D           = document;
    var scriptNode  = D.createElement ('script');
    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);
}