13

I have a greasemonkey script for Firefox, which yesterday was working perfectly. I tried using it today (no code was modified) and I noticed that it stopped working. Upon further inspection, the script is now throwing the following error:

Error: Permission denied to access property 'handler'

This error is being thrown in the following block of code:

$('body').click(function() {
    // code here
});

This error magically started happening today when the script was working just fine yesterday. I'm not understanding why this error is happening when just trying to do something so basic such as adding an event handler in jQuery.

My script uses jQuery which is already being used in the page the script executes on, so I used this code to make it accessible to GM:

var $ = unsafeWindow.jQuery;

For reference if need be, here are the following Greasemonkey functions I use in my script:

// @grant       GM_getResourceText
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// @grant       GM_getResourceURL

I have tried researching this error and I can't find any answer. All of the questions that look like they might be helpful involve iframes and there is not a single iframe to be found in my code or the website it's run on. I've also tried deleting and re-installing the script and that didn't fix the problem.

user3810422
  • 287
  • 2
  • 3
  • 5

3 Answers3

20

Greasemonkey 2.0 has just been pushed to all Firefox browsers set to auto-update. (GM 2 was released on June 17, 2014, but it can take a few weeks to get through the review process.)

Greasemonkey 2.0 radically changed unsafeWindow handling:

Backwards incompatible changes:

  • For stability, reliability, and security the privileged sandbox has been updated to match the new changes to unsafeWindow for the Add-on SDK. In order to write values to unsafeWindow you will need to use the new methods cloneInto(), exportFunction(), and/or createObjectIn().
  • The @grant none mode is now the default, and grants will no longer be implied when not explicitly provided. See the post Sandbox API Changes in Greasemonkey 2.0 for more detail.

Ordinarily, to spot-access a page function or variable, you could switch to the new methods but, in your case you are using var $ = unsafeWindow.jQuery; -- which was always a bad practice.

jQuery is a special case and cloning it back and forth is going to break things.
@require jQuery instead, EG:

// ==UserScript==
// @name        _YOUR_SCRIPT_NAME
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @grant       GM_getResourceText
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// @grant       GM_getResourceURL
// ==/UserScript==
...
Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • 4
    Thank you! cloneInto() worked for me. In my case I tried to pass an object to another script from my GM script, and when that other script tried to access it it threw a permission denied error. – Thomas Glaser Jul 14 '14 at 20:28
  • 4
    MDN articles: [`cloneInto`](https://developer.mozilla.org/en-US/docs/Components.utils.cloneInto), [`exportFunction`](https://developer.mozilla.org/en-US/docs/Components.utils.exportFunction), [`createObjectIn`](https://developer.mozilla.org/en-US/docs/Components.utils.createObjectIn) – Oriol Aug 22 '14 at 17:01
  • MDN links are broken, so just adding this as a quick example for injecting an object with a nested function (`foo = {bar: function(){..}`): `unsafeWindow.foo = cloneInto({}, unsafeWindow); unsafeWindow.foo["bar"] = exportFunction(function() {}, unsafeWindow.foo);` – Janaka Bandara Nov 15 '21 at 02:35
0

You're using unsafeWindow – that, as the name suggested, is not necessary "safe" to use – the problem probably relies there; a change was made in Firefox about objects across compartments:

https://blog.mozilla.org/addons/2014/04/10/changes-to-unsafewindow-for-the-add-on-sdk/

The blog post mention Add-on SDK, but the changes is in the platform, so it will affect Greasemonkey too.

So you basically try to get an object from one compartment (jQuery, from "unsafeWindow") and use in your greasemonkey sandbox. The way you're doing now probably can't work anymore. You can try to use the API mentioned in the article, but I'm afraid that a whole library like jQuery could have some issue to be cloned. In fact, the best way is probably load jQuery also in your Greasemonkey compartment instead of reuse the one from the page's one.

The error probably started "magically" 'cause you have updated your version of Firefox – or it gets the autoupdated.

ZER0
  • 24,846
  • 5
  • 51
  • 54
  • This is not a SDK change, is a platform change that affect how SDK works, in fact the article specified that also the usage of `wrappedJSObject` is affected – that means, regardless the SDK. I know that because I'm in the team that did that change. I do not know GM well, but as said, it's a platform change, and GM is built on top of it. I have no idea how they decide to handle such new restriction, but are there regardless GM or SDK. – ZER0 Jul 13 '14 at 06:20
  • [`wrappedJSObject` docs](https://developer.mozilla.org/en-US/docs/wrappedJSObject) show no such change. And AFAICT, Scriptish isn't affected in the same way. That article talks exclusively about the SDK making changes, it does not mention any changes on Firefox itself -- although we know that those 3 `Components.utils` functions are new. – Brock Adams Jul 13 '14 at 06:32
  • 1
    Also, important to note: FF 30 did not break these `unsafeWindow` scripts. GM 2.0 did that. – Brock Adams Jul 13 '14 at 06:40
  • It could be that the docs if `wrappedJSObject` are outdate, I'll check with my team mate. Notice that this change is specifically about different compartments with different privileges, like a sandboxed environment like SDK or GM, and a content environment. The article is focused on SDK because there we had the major impact – GM is not by Mozilla. It could be that Scriptish doesn't match this case. You can find plenty of changes in Firefox platform about that in Bugzilla under Core/XPConnect. Again, it's not a SDK changes; it's just affect mostly SDK in our case. – ZER0 Jul 13 '14 at 06:42
  • You're right. A (coming) change in FF drove the SDK change and, in turn, the GM change. So, even if GM didn't have to break things just yet (or in such an install-base crippling way), the change was going to happen anyway. – Brock Adams Jul 13 '14 at 06:54
0

This page explains how to load jQuery in a Greasemonkey script: http://wiki.greasespot.net/Third-Party_Libraries

The relevant parts are:

// @require       http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
...
this.$ = this.jQuery = jQuery.noConflict(true);

According to the docs, jQuery.noConflict() will make sure the version of jQuery for your script won't interfere with the page.

See also: jQuery in Greasemonkey 1.0 conflicts with websites using jQuery

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • `noConflict` is superfluous when a `@grant` other than `none` is used -- as in this question's case. `@require` was already covered in my answer. – Brock Adams Jan 02 '15 at 01:04
  • @BrockAdams: My understanding is that the code above always works, no matter which `@grant`s are enabled. The important part of my question is that this is the official solution. – Aaron Digulla Jan 05 '15 at 09:40
  • The "official" solution says you can **either** use `noConflict(true)` **or** use a proper `@grant` value. *This* question is a grant {plenty} scenario, so that code is a waste of time and a potential "head scratcher" on later review. – Brock Adams Jan 05 '15 at 10:14
  • @BrockAdams: This doesn't work with the latest Firefox (34? 35?) and GM anymore. I had the `@grant` and I could access `unsafeWindow` and `unsafeWindow.$` but `unsafeWindow.$.each()` now fails with "accessing `call()` from different context". My guess is that the official documentation is outdated with regards to this. – Aaron Digulla Jan 05 '15 at 10:23
  • Problem's unclear in your last comment. `unsafeWindow.$` has not worked for the last half year if a `@grant` was set. Error message may vary. Open a new question if you need to. – Brock Adams Jan 05 '15 at 10:34
  • @BrockAdams: I'm saying that calling functions in the page's jQuery instance doesn't work anymore, no matter what kind of grants you have or don't have. – Aaron Digulla Jan 05 '15 at 13:14
  • No, `unsafeWindow.$.each(...` still works perfectly fine when `@grant none` is in effect. I just double checked on the latest FF *release* (34.0.5). That's because in that mode `unsafeWindow === window`. – Brock Adams Jan 05 '15 at 22:19
  • @BrockAdams: Can you check again with `@grant unsafeWindow`? – Aaron Digulla Jan 06 '15 at 15:59
  • `@grant unsafeWindow` switches back on the sandbox and results in the same scenario as the OP's question -- so you will have the same problem for the same reasons (but possibly different error message). – Brock Adams Jan 06 '15 at 21:43