关闭`@grant none`会破坏我的Greasemonkey脚本?

6

我正在Facebook首页上运行这个脚本。它获取底部的对话框中的所有对话,并获取它们的__FB_TOKEN

// ==UserScript==
// @name MyScript
// @namespace MyNameSpance
// @include /https?://(www.)?facebook.com(/.*)?/
// @require http://code.jquery.com/jquery-2.1.0.min.js
// @version 0.0.0
// @grant none
// ==/UserScript==
(function () {
  // Don't run on frames or iframes
  if (window.top != window.self) {
    return ;
  }

  window.addEventListener('load', function () {

    var element = $('.fbNubGroup.clearfix.videoCallEnabled');
    console.log('SCRIPT ELEMENT: ', element); // is displayed on the console

    var children = element.children();
    console.log('SCRIPT CHILDREN: ', children); // is displayed on the console

    for (var i = 0; i < children.length; i++) {
      var child = $(children[i]);
      console.log('SCRIPT CHILD: ', child); // is displayed on the console

      /*
      child :
        Object [div.someClasses]
          + 0: div.someClasses
            + __FB_TOKEN: [ 267 ]
      */

      console.log('SCRIPT CHILD[0]: ', child[0]); // is displayed on the console
      console.log('SCRIPT CHILD[0].__FB_TOKEN:', child[0].__FB_TOKEN); // UNDEFINED

      var key = child[0].__FB_TOKEN[0];
      console.log('SCRIPT KEY: ', key); // not displayed
    }
  }, false);
}) ();


使用@grant none,它按预期工作并返回:

grant_none

然而,如果我将@grant none更改为@grant GM_xmlhttpRequest,脚本将不再起作用。它会显示:

grant GM_xmlhttpRequest

我不明白为什么在child[0].__FB_TOKEN这一行会抛出异常,因为CHILD[0]没有改变:


child

为什么更改@grant none会破坏脚本?
1个回答

10
当您从 @grant none 切换到 @grant GM_xmlhttpRequest 时,Greasemonkey会将沙盒重新打开,这是一个副作用
(坦白地说,所有GM开发人员和脚本都应始终以沙盒开启--极为罕见��例外情况除外。这避免了“定时炸弹”编码问题和类似于此问题的难题。) JavaScript对象,数组,变量和函数不能跨越沙盒。但是, unsafeWindow 被提供给Greasemonkey范围作为有限的解决方法。
此问题还很重要:
  1. Greasemonkey(和Firefox)刚关闭了以前使用 unsafeWindow 的一些可能解决方案
  2. jQuery是特殊情况,使用它将非DOM对象带入沙盒更加困难。

解决方案:

  1. 由于 __FB_TOKEN 是一个数组,因此必须使用 unsafeWindow 来将其传递到沙盒之外。
  2. 在此情况下尝试使用jQuery会导致结果与头痛程度不成正比,因此请使用普通的DOM方法。
将所有内容组合起来,脚本变为:
// ==UserScript==
// @name        _MyScript
// @namespace   MyNameSpace
// @include     /https?://(www.)?facebook.com(/.*)?/
// @require     http://code.jquery.com/jquery-2.1.0.min.js
// @version     0.0.0
// @grant       GM_xmlhttpRequest
// ==/UserScript==
(function () {
    // Don't run on frames or iframes
    if (window.top != window.self) {
        return;
    }
    window.addEventListener ('load', function () {
        /*--- This unsafeWindow is key. After that, don't use any jQuery
            while trying to get at javascript objects like __FB_TOKEN.
        */
        var element = unsafeWindow.document.querySelector (
            '.fbNubGroup.clearfix.videoCallEnabled'
        );
        /*-- Used console.info to make it easier to spot messages buried
            in all the Facebook console crud.
        */
        console.info ('SCRIPT ELEMENT: ', element);

        var children = element.children;
        console.info ('SCRIPT CHILDREN: ', children);

        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            console.info ('SCRIPT CHILD: ', child);

            /*
            child :
              Object [div.someClasses]
                + 0: div.someClasses
                  + __FB_TOKEN: [ 267 ]
            */
            console.info ('SCRIPT CHILD: ', child);
            console.info ('SCRIPT CHILD.__FB_TOKEN:', child.__FB_TOKEN);

            var key = child.__FB_TOKEN[0];
            console.info ('SCRIPT KEY: ', key);
        }
    }, false);
} ) ();

非常感谢您提供的所有细节。首先,您知道为什么Chrome不受沙盒影响吗?我的意思是,这不是我的真正脚本,但这个逻辑被用在一个更大的脚本中。在Chrome中,从none到GM_xml...的切换并没有改变任何东西,我的脚本可以工作(我没有测试过这个)。--其次,我听说过沙盒,但我不知道它的后果,谢谢!--最后,作为一个快速修复(因为我已经在使用jQuery了),我最终使用了element = $(unsafeWindow.document.querySelector('.fbNubGroup.clearfix.videoCallEnabled')); - AlixB
你在Chrome中使用Tampermonkey吗? Chrome沙盒与FF沙盒非常不同。 Chrome + Tampermonkey试图模拟FF + GM,但它并不完全匹配并且会随着变化而改变...很高兴现在$(unsafeWindow ...可以工作,但这种方法可能会在未来导致更多的困惑。;) - Brock Adams
我正在使用Tampermoney。是的,我确实注意到它与Greasemonkey不同(例如,在Facebook首页上,window.load事件的触发时间不同。我必须在Tampermonkey上使用$(document).ready使脚本等待足够长的时间)。-- 是的,对于$(...)这只是一个快速修复。在不久的将来,我会尽可能删除关于jQuery的所有内容!再次感谢您的准确信息!! - AlixB
你不需要移除所有的jQuery。只要不将其用作提取目标页面定义的javascript变量的一部分即可。 - Brock Adams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接