以不可检测/可逆的方式更改Window.prototype.open

Wla*_*ant 14 javascript firefox firefox-addon firefox4 prototype-programming

我正在研究如何从扩展中扩展Firefox弹出窗口阻止.一种选择是通过包装函数替换window.open()(或更确切地说Window.prototype.open())网页.一个重要的要求是网页无法检测或恢复此操作.例如,如果我只是这样做:

Window.prototype.open = wrapper;
Run Code Online (Sandbox Code Playgroud)

通过执行以下操作,网页可以轻松恢复更改:

delete Window.prototype.open;
Run Code Online (Sandbox Code Playgroud)

相反,我可以使用Object.defineProperty()来设置高级属性标志:

Object.defineProperty(Window.prototype, "open", {value: wrapper, configurable: false});
Run Code Online (Sandbox Code Playgroud)

网页无法再恢复此更改,但它仍然可以检测到它:delete Window.prototype.open通常会更改Window.prototype.open(看起来相同功能的不同实例)的值,这里delete根本不会产生任何影响.此外,Window.prototype.open = "test";delete Window.prototype.open;将产生不一致的结果(不同的结果取决于是否writable: false为属性指定了标志).

还有什么我可以做的来模仿原始属性的行为(没有使用二进制XPCOM组件,它有太多自己的问题)?

Mat*_*ner 7

您可以尝试使用该nsIWindowWatcher界面注册您自己的窗口创建者(nsIWindowCreator).这样,您可以控制是否打开新窗口而不影响窗口对象本身(因此对网站保持不可见).

我不确定在window.open()没有这个可检测的情况下是否无法改变实现是一个错误.也许它不被认为是像这样的方法的重要要求Object.defineProperty.但是可能值得提出一个错误,看看其他人在将来考虑将其作为一种选择.毕竟,广告拦截是一个主要的用例.


Wla*_*ant 4

最后我不得不放弃使用 JavaScript 代理来完成这项工作。尽管经过一些努力,我可以创建一个与window.open()原始函数完全相同的包装器(需要考虑错误 650299),但似乎没有合适的方法来替换原始window.open()函数。更改后的属性的行为总是与原始属性不同,这太糟糕了。

因此,我决定采用不同的方法作为弹出窗口阻止解决方案:监听content-document-global-created通知并查看主题(新窗口)及其开启者。具有非空开启器的窗口是某种弹出窗口。人们可以查看 URL 并决定是否应阻止弹出窗口。要阻止一个会调用window.stop()(在发送任何网络请求之前停止所有网络活动)和window.close(). 后者必须异步调用(有延迟),因为否则在窗口初始化继续时会导致崩溃。关于此方法的一些注意事项:

  • 对于在新窗口中打开的弹出窗口,该窗口仍会显示,但会立即消失。这似乎是不可避免的。
  • 对于网页来说,它的弹出窗口看起来像是打开了,但立即关闭了 - 这不是内置弹出窗口阻止程序的工作原理,更像是外部弹出窗口阻止应用程序。
  • 新窗口始终about:blank先加载,然后再更改为实际目的地。对于同源弹出窗口,后者不会发送新的content-document-global-created通知,这是不幸的。

总而言之:不完美但可用。而且它非常简单,远不及 JavaScript 代理所需的代码量。