Greasemonkey and avoiding the sandbox
Recently, I was trying to write a greasemonkey script to override the HTMLHeadElement.appendChild function in the browser DOM. Well, the reason I was trying to do that was to redirect a json-p call to my servers instead of the once mentioned in the webpage. Json-p works by dynamically adding a script tag to get around the cross-domain restriction policy of browsers. So, in most cases the script tag is added to the "
" element. What I was trying to do was :
HTMLHeadElement.prototype._appendChild = HTMLHeadElement.prototype.appendChild;
HTMLHeadElement.prototype.appendChild = function(node) {
if(node.nodeName == "SCRIPT") {
var new_src = "http://foo.com/?...";
node.setAttribute("src", new_src);
}
HTMLHeadElement.prototype._appendChild.apply(this,arguments);
}
Well, this script worked on the Firefox console. But, it turns out it does not work as a Greasemonkey script. The reason being the greasemonkey scripts are run as part of a sandbox, and so do not have access to all the window elements. ( I wonder why ? ) . I even tried using "unsafewindow" , but even that does not work. You get access to HTMLHeadElement, but HTMLHeadElement.prototype is undefined. So, what now ?
Well, there is a simple workaround. Just modify your greasemonkey script to run the above code as part of the script in page. Basically, create a script tag, and add the abpve script as part of the script. Now since, this code will run in the context of the page and not in the context of the greasemonkey script, you will not have to worry about any restrictions imposed by the greaemonkey script. I basically put all my code in a separate js file and then loaded that into the script tag using greasemonkey:
var scriptElement = document.createElement("script");
scriptElement.setAttribute("src", "new_js.js");
scriptElement.setAttribute("type", "text/javascript");
document.body.appendChild(scriptElement);
And, there is another advantage to writing greasemonkey scripts this way, you separate out the main javascript from the greasemonkey script. And now you can keep updating your javascript and the users can keep getting the updated functionality without them re-installing the greasemonkey script again. Sweet!
