I am looking into ways to extend Firefox pop-up blocking from an extension. One option is replacing window.open() (or rather Window.prototype.open()) in the webpage by a wrapper function. An important requirement is that this manipulation cannot be detected or reverted by the webpage. For example, if I simply do this:
Window.prototype.open = wrapper;
The webpage can easily revert the change by doing:
delete Window.prototype.open;
Instead I can use Object.defineProperty() to set advanced property flags:
Object.defineProperty(Window.prototype, "open", {value: wrapper, configurable: false});
The webpage can no longer revert this change but it can still detect it: delete Window.prototype.open normally changes the value of Window.prototype.open (different instance of the same function it seems), here delete won’t have any effect at all. Also, Window.prototype.open = "test";delete Window.prototype.open; will produce inconsistent results (different ones depending on whether writable: false flag is specified for the property).
Is there anything else that I can do to emulate the behavior of the original property (short of using binary XPCOM components which has way too many issues of its own)?
In the end I had to give up on using JavaScript proxies for the job. Even though with some effort I can create a wrapper for
window.open()that behaves exactly like the original (bug 650299 needs to be considered), there doesn’t seem to be a proper way to replace the originalwindow.open()function. The changed property will always behave differently from the original one, too bad.So I decided to go with a different approach as a pop-up blocking solution: listen for
content-document-global-creatednotification and have a look at the subject (the new window) as well as its opener. Windows with a non-null opener are pop-up windows of some kind. One can look at the URLs and decide whether the pop-up should be blocked. To block one would callwindow.stop()(stops all network activities before any network requests are sent) andwindow.close(). The latter has to be called asynchronously (with a delay) because it will cause a crash otherwise as the initialization of the window continues. Some notes on this approach:about:blankfirst before changing to their actual destination. For same-origin pop-ups the latter won’t send a newcontent-document-global-creatednotification which is unfortunate.All in all: not perfect but usable. And it is very simple, nowhere near the amount of code required for JavaScript proxies.