There are a few questions relating to this, but the general 'solution' of using unsafeWindow
isn't working for me.
I'm trying to use the Stack Exchange Javascript SDK.
This works:
// ==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');
}
});
This doesn't:
// ==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');
}
});
However, both versions log Object { authenticate: n(), init: r() }
for the console.log(SE)
which I can't understand because it means the script has access to the SE object.
By "doesn't work", I mean it does nothing; nothing is logged to the console after the first console.log(SE)
.
I don't understand how to get this library to work. Does anyone have any ideas? This is relating to the sandbox that is enabled on Firefox when a grant value is set.
This does, by the way, work on Chrome either way, but my understanding is that the 2 sandboxes are considerably different. Is there any way to get around this Firefox sandbox that is preventing the SE.init()
function to run? I've tried unsafeWindow.SE...
but that doesn't work -- I don't think it should make a difference because the script always has access to the SE object; it's just having trouble actually calling it!
A quick hack would be to inject your entire code, including the simple-API script, into webpage and use messaging (dispatchEvent + addEventListerner for 'message' event on window object) to access GM_
functions that aren't available for an injected script.
It's not as secure as a GM sandbox: the API key can be intercepted via DOM mutation observer / listener or onbeforescriptexecute
event listener if you have installed an extension or userscript that is specifically targeted to steal the key.
// ==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();'
The API script is declared as a resource so that it's downloaded only once, when the script is installed, and stored on the user's hard drive alongside the script.
Alternatively, inject the API and call it via unsafeWindow
and exportFunction
for your callbacks:
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),
});
A proper solution is to access the actual API manually via GM_xmlhttpRequest until someone publishes a better library. In Tampermonkey you'll also need to add a permission for the API url:
// @connect api.stackexchange.com
.