0.7.20080121.0 compatibility

From GreaseSpot

Jump to: navigation, search

Greasemonkey 0.7.20080121.0 introduced a change to work around a potential security problem which could break some previously working scripts.

Starting at this version, GM "double-checks" the call stack of all calls into potentially unsafe Greasemonkey APIs to make sure that every frame on the stack is either from a user script, or from the browser DOM. The APIs that currently have this check are:

 * GM_xmlhttpRequest
 * GM_getValue
 * GM_setValue
 * GM_getResourceURL (new in 0.8)
 * GM_getResourceText (new in 0.8)

This means that you cannot register a callback with content-defined JavaScript and call one of these GM APIs from that callback. Code like below will not work:

unsafeWindow.someObject.registerCallback(function() {
  GM_setValue("foo", "bar");
});

or

unsafeWindow.someAPIfunction = function() {
  GM_setValue("foo", "bar");
};

Here is a workaround for this limitation:

unsafeWindow.someObject.registerCallback(function() {
  window.setTimeout(function() {
    GM_setValue("foo", "bar");
  }, 0);
});

and

unsafeWindow.someAPIfunction = function() {
  window.setTimeout(GM_setValue, 0, "foo", "bar");
};

or, if you have a lot of them, perhaps this:

function safeWrap(f) {
  return function() {
    setTimeout.apply(window, [f, 0].concat([].slice.call(arguments, 1)));
  };
}

unsafeWindow.someAPIfunction = wrap(function() {
  GM_setValue("foo", "bar");
});

Take care with untrusted input when using this workaround. Remember that since someObject is a property of unsafeWindow it might not contain the code you expect it to. For example, the below is not safe because it blindly requests a URL that originated in unsafeWindow.

unsafeWindow.someObject.registerCallback(function(url) {
  window.setTimeout(function() {
    GM_xmlhttpRequest({
       method: "GET",
       url: url
    });
  }, 0);
});

Here is a safer version:

unsafeWindow.someObject.registerCallback(function(asin) {
  window.setTimeout(function() {
    GM_xmlhttpRequest({
       method: "GET",
       url: "http://www.amazon.com/asin/" + asin;
    });
  }, 0);
});

In this example, you know that your user script can only ever be used to make requests to amazon.com.

Personal tools