unsafeWindow 内から GM_* や window.eval を使う

http://d.hatena.ne.jp/janus_wel/20090105/1231172789 でどうにかならないかと言ってた unsafeWindow 内から GM_xmlhttpRequest を使う方法なんだけど、 http://wiki.greasespot.net/0.7.20080121.0_compatibility の最後の方に対処法が載ってた。要は window.setTimeout を使って scope chain を断ち切る & 安全な ( であると思われる ) window object 内で実行することで安全性を確保するという仕組みらしい。で、実際に使うにあたって http://nanto.asablo.jp/blog/2008/02/14/2626240 で説明されている Array generics ( https://developer.mozilla.org/ja/New_in_JavaScript_1.6#Array_.E3.81.8A.E3.82.88.E3.81.B3_String_.E3.81.AE.E6.B1.8E.E7.94.A8.E5.8C.96 ) を使って以下のように書き直してみた ( Array.slice の意味も上記の nanto_vi さんとこでわかりやすく説明されているので参照するとよいかも ) 。

function wrapSecurely(f) {
     return function () {
         setTimeout.apply(window, [f, 0].concat(Array.slice(arguments)));
     };
}

使うときは以下のような感じで wrap された関数を取得 & 実行する。 GM_getValue, GM_setValue, GM_xmlhttpRequest は wrap しないとダメみたいなので unsafeWindow でこちゃこちゃやるんならあらかじめ定義しとくといいかもしれない。

wrapSecurely( function () {
    GM_xmlhttpRequest({
        method: 'GET',
        url: 'http://example.com/foo.json',
        onload: function (r) {
            GM_log(r.responseText);
        }
    });
})();

ついでに unsafeWindow 内で eval を呼ぼうとするとやっぱり怒られるので、上記のカラクリと同じように eval.call で window object を指定して実行 context を明示するとよい感じ ( http://d.hatena.ne.jp/brazil/20060821/1156164845 ) 。

var o = eval.call(window, '(' + r.responseText + ')');

あと今まで unsafeWindow についてとにかく危険という適当な理解しかしてなかったんだけど http://wiki.greasespot.net/UnsafeWindow に何ができるのかちゃんと書いてあった。 page 側が仕込んだ object, function, variable etc をいじれるのね。危険だって言われてる割にみんな当たり前のように使うから不思議だったんだけどやっと理由がわかったよ ( 鈍男 ) 。というわけで、これで大体 Greasemonkey を書く上での道具が整ったかなという状況。