当设置了@grant值时,不能使用所需库

Can't use required library when an @grant value is set

本文关键字:不能 设置 @grant 值时      更新时间:2023-09-26

有一些与此相关的问题,但使用unsafeWindow的一般"解决方案"不适合我。

我正在尝试使用Stack Exchange Javascript SDK。

如此:

// ==UserScript==
// @name        testing
// @include     http://stackoverflow.com/*
// @require     https://api.stackexchange.com/js/2.0/all.js
// @version     1
// @grant       none
// ==/UserScript==
console.log(SE);
SE.init({
  clientId: 1234,
  key: 'my key',
  channelUrl: location.protocol + '//stackoverflow.com/blank',
  complete: function (d) {
    console.log(d);
    console.log('SE init');
  }
});

这并不:

// ==UserScript==
// @name        testing
// @include     http://stackoverflow.com/*
// @require     https://api.stackexchange.com/js/2.0/all.js
// @version     1
// @grant       GM_setValue
// ==/UserScript==
console.log(SE);
SE.init({
  clientId: 1234,
  key: 'my key',
  channelUrl: location.protocol + '//stackoverflow.com/blank',
  complete: function (d) {
    console.log(d);
    console.log('SE init');
  }
});

然而,两个版本都为console.log(SE)记录Object { authenticate: n(), init: r() },我无法理解,因为这意味着脚本可以访问SE对象。

"不工作",我的意思是它什么也不做;在第一个console.log(SE)之后没有任何内容被记录到控制台。

我不知道如何让这个库工作。有人有什么想法吗?这与设置授予值时在Firefox上启用的沙箱有关。

这确实,顺便说一句,在Chrome上的工作方式,但我的理解是,这两个沙箱是相当不同的。有没有办法绕过这个阻止SE.init()功能运行的Firefox沙盒?我试过unsafeWindow.SE...,但这不起作用——我不认为它应该有所不同,因为脚本总是可以访问SE对象;它只是很难调用它!

一个快速hack将注入你的整个代码,包括简单的api脚本,到网页和使用消息传递(dispatchEvent + addeventlistener 'message'事件在窗口对象)访问GM_函数不可用于注入的脚本。

它不像GM沙箱那样安全:如果您安装了专门针对窃取密钥的扩展或用户脚本,则可以通过DOM突变观察者/侦听器或onbeforescriptexecute事件侦听器截获API密钥。

// ==UserScript==
// @name        testing
// @include     http://stackoverflow.com/*
// @include     https://stackoverflow.com/*
// @resource    SE_JS_API https://api.stackexchange.com/js/2.0/all.js
// @version     1
// @grant       GM_setValue
// @grant       GM_getResourceText
// ==/UserScript==
document.head.appendChild(document.createElement('script')).text =
  GM_getResourceText('SE_JS_API') + ';(' + function() {
    SE.init({
      clientId: 1234,
      key: 'my key',
      channelUrl: location.protocol + '//stackoverflow.com/blank',
      complete: function (d) {
        console.log(d);
        console.log('SE init');
      }
    });
  } + ')(); this.remove();'

API脚本被声明为资源,因此它只在脚本安装时下载一次,并与脚本一起存储在用户的硬盘上。

或者,注入API并通过unsafeWindowexportFunction为回调调用它:

document.head.appendChild(document.createElement('script')).text =
  GM_getResourceText('SE_JS_API');
unsafeWindow.SE.init({
  clientId: 1234,
  key: 'my key',
  channelUrl: location.protocol + '//stackoverflow.com/blank',
  complete: exportFunction(function (d) {
    console.log(d);
    console.log('SE init');
  }, unsafeWindow),
});

一个合适的解决方案是通过GM_xmlhttpRequest手动访问实际的API,直到有人发布更好的库。在Tampermonkey中,你还需要为API url添加权限:
// @connect api.stackexchange.com .