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 original window.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-created
notification 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 call window.stop()
(stops all network activities before any network requests are sent) and window.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:blank
first before changing to their actual destination. For same-origin pop-ups the latter won't send a new content-document-global-created
notification 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.