More about Greasemonkey: Sandbox

October 29, 2007 – 6:18 pm

我在上一篇 Blog 中简单地介绍了 Greasemonkey 。并推荐了 Dive into Greasemonkey 这个教程。这次我要介绍的是 Greasemonkey 的沙盒。其实我见过一个朋友在这上面碰过钉子,我自己也正好碰到了问题,便去 GM 的 wiki 上查找了相关的资料。这里把我知道的共享出来,免得有朋友再走弯路,因为 Dive into Greasemonkey 里面的一个例子也是无法正确执行的,也许是教程有些旧了的缘故吧,GM 沙盒也是在不断完善的。

事情的起因是我想要写一个用户脚本让我在 学校的 cc98 论坛发帖的时候自动加上定义好的签名档,要模仿 Dive into Greasemonkey 里面的那个例子来修改 submit()

// If a script calls someForm.submit(), the onsubmit event does not fire,
// so we need to redefine the submit method of the HTMLFormElement class.
HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = newsubmit;

然而运行却出错了:

HTMLFormElement.prototype has no properties

我搜索了下也没发现解决办法,便用 alert 进行调试,后来我发现在 GM 脚本环境里面的 window 对象和页面里面普通脚本环境里面的 window 对象似乎是不一样的。我知道为了不和已有脚本产生混乱,GM 脚本被包含在一个匿名的函数中,然而我却没想到直接引用 window 对象竟然也是有区别的。

无奈之下我便去 GM 的 wiki 去看看能否找到有用的东西,正好看到了 sandbox 这个东西。事实上,由于安全原因,GM 脚本被放在 sandbox 中运行,不止是包围在一个匿名函数中防止名字冲突,而且网页中原有的大部分对象都通过 XPCNativeWrapper 包装过了。不过哦像这样可以访问到被包装的对象:

var realObj = wrappedObj.wrappedJSObject;

这样包装虽然大部分情况下是透明的,但是也有一些区别。例如,Expando Properties 就不能透明地应用到被包装的对象上,onclick 正好是一个 Expando Property ,所以下面的代码在 GM 里面无法工作:

var el=document.createElement('a');
el.onclick='alert("Error"); return false;'

我想小强正好是遇到这个问题的吧,结果他说 Firefox 不支持这种事件模型,我虽然知道 Firefox 确实支持 onclick ,但是当时看到他的代码不能运行,也不知道是什么道理。还有其他的差别,在 GM 的 wiki 列举了一些。

我碰到的问题也是差不多的,window 是一个包装对象,要使用原来的 window ,可以通过 unsafeWindow 变量来引用到,在 GM wiki 的 unsafeWindow 一节也讲到了,我把上面的代码改成下面这样:

unsafeWindow.HTMLFormElement.prototype._submit = unsafeWindow.HTMLFormElement.prototype.submit;
unsafeWindow.HTMLFormElement.prototype.submit = newsubmit;

就可以工作了。不过 GM 的 wiki 上极力强调 unsafeWindow 是及其不安全的,应该避免使用。但是我也暂时想不到其他好办法了,反正这个脚本只是我自己玩玩。至少我知道是怎么回事了。 :)

Post a Comment