【问题标题】:Why does changing grant from none to GM_xmlhttpRequest break my code?为什么将授权从无更改为 GM_xmlhttpRequest 会破坏我的代码?
【发布时间】:2017-03-30 03:30:35
【问题描述】:

简而言之,我不想将警报 URL 和响应正文发送到我的应用程序。此代码有效,但除非我同意,否则我不能使用 GM_xmlhttpRequest。

什么都不改变,代码就会神奇地中断。我不确定发生了什么变化以及如何修复它。我以为我可以使用console.log 并将数据复制/粘贴到我的应用程序中,但是 Facebook 禁用了 console.log。

我想过做 xmlhttpRequest 但这也以某种方式被阻止了。我通过在控制台中执行代码进行了测试。除了 Facebook 域之外,这 3 行似乎在任何地方都有效。我认为这与 CORS 有关。

// ==UserScript==
// @name        FBTest
// @namespace   test
// @include     https://*.facebook.com/*
// @version     1
// @grant       none
// ==/UserScript==
//change none to GM_xmlhttpRequest
(function() {
    var proxied = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function(method, url) {
        alert(url);
        return proxied.apply(this, [].slice.call(arguments));
    }; 
})();

【问题讨论】:

  • 使用GM_xmlhttpRequest 而不是window.XMLHttpRequest
  • @Mottie - 代码试图“拦截” XMLHttpRequest 的打开函数,而不是实际使用 XMLHttpRequest
  • 问题源于这样一个事实,即任何带有@grant anything other than none 的脚本都在更安全的范围内运行。我最初认为您可以使用 unsafeWindow 而不是 window - 但是,这也不起作用,因为 .open 然后由于您的 open 代码在其中运行的特权范围而从页面中呈现为不可用。
  • 使用Add-on SDK 甚至WebExtensions 会更幸运

标签: javascript facebook greasemonkey userscripts tampermonkey


【解决方案1】:

当您授予 GM_xmlhttpRequest 时,it switches on the sandbox -- 这意味着您不能像现在这样访问 window.XMLHttpRequest,因为它现在处于不同的上下文中。

要解决此问题,请使用script injection 拦截 AJAX。并且,使用messaging 或自定义事件来访问用户脚本上下文中的数据。

这是一个使用自定义事件的示例脚本(不易受到 3rd-party 攻击):

// ==UserScript==
// @name        _Intercept AJAX with grant/sandbox on
// @match       https://*.facebook.com/*
// @grant       GM_xmlhttpRequest
// ==/UserScript==

function xmlOpenIntercept () {
    var proxied = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function (method, newUrl) {
        var cEvnt = new CustomEvent ('newAjaxStart', {'detail': newUrl} );
        document.body.dispatchEvent (cEvnt);

        return proxied.apply (this, [].slice.call (arguments) );
    };
}
addJS_Node (null, null, xmlOpenIntercept);  //-- Injects code


//--- This code listens for the right kind of message.
document.body.addEventListener ("newAjaxStart", receiveAjaxMessage);

function receiveAjaxMessage (zEvent) {
    console.log ("Intercepted AJAX to: ", zEvent.detail);
}

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

【讨论】:

  • 仅供参考,document.head 自 4.0 以来一直在 Firefox 中 - 不再需要 getElementsByTagName
  • @JaromandaX,除非脚本运行时不存在 1 个 <head>
  • 我从来没有考虑过! - 顺便说一句,很好的答案,也帮助了我:p
  • 此外,此功能早于 FF 4 和 document.head 需要 IE9 或更高版本。还不允许放弃早期的 IE 支持。
  • 我没有意识到我的所有数据都必须在detail 中。在我发现这个解决方案有效之后。
猜你喜欢
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
相关资源
最近更新 更多