バックグラウンド
Greasemonkey は私の拡張機能 JavaScript を既に挿入していませんか? 誰かが私のためにこれを明確にしてください。
Greasemonkey は、ページ内の JavaScript に直接アクセスできない制限された環境であるサンドボックスでスクリプトを実行します。Greasemonkey の以前のバージョンでは、スクリプトをページに直接挿入していましたが、これにより深刻なセキュリティ上の脆弱性が生じていました。古いモデルでは、スクリプトはブラウザ クロームの昇格された権限で実行され、リモート ページは巧妙な JavaScriptを使用して Greasemonkey の組み込み関数にアクセスできました。これは悪かった:
Greasemonkey スクリプトには独自の GM_xmlhttprequest オブジェクトが含まれており、通常の xmlttprequest オブジェクトとは異なり、通常 xmlhttprequest に適用される同一オリジン ポリシーに関係なく、コンピュータの任意のローカル ファイルにアクセスしたり、任意のサイトに任意のリクエストを作成したりできます。(ソース)
window
現在、Greasemonkey スクリプトからオブジェクトにアクセスすると、実際の のプロパティを間接的に参照するラッパー オブジェクトが得られます。window
このラッパー オブジェクトは安全に変更できますが、重要な制限があります。実際のウィンドウ オブジェクトへのアクセスはunsafeWindow
(の省略形window.wrappedJSObject
) によって提供されます。を使用するとunsafeWindow
、Greasemonkey の元のセキュリティ問題がすべて再び発生し、Chrome では利用できません。可能な限り避けるべきです。
幸いなことに、Greasemonkey の新しいセキュリティ モデルを安全に使用するには、少なくとも 2 つの方法があります。
スクリプト インジェクション
Greasemonkey スクリプトが DOM に安全にアクセスできるようになったので、ターゲット ドキュメントの にタグを挿入するのは簡単です。<script>
<head>
次のような関数を作成します。
function exec(fn) {
var script = document.createElement('script');
script.setAttribute("type", "application/javascript");
script.textContent = '(' + fn + ')();';
document.body.appendChild(script); // run the script
document.body.removeChild(script); // clean up
}
使い方は簡単です:
exec(function() {
return Grooveshark.playNextSong();
});
ロケーションハック
スクリプト インジェクションは場合によってはやり過ぎかもしれません。特に、必要なのはページ内の変数の値を変更するか、単一の関数を実行することだけである場合です。Location Hackは、javascript:
URL を利用してドキュメントのコンテンツ内のコードにアクセスします。これは、Greasemonkey スクリプト内からブックマークレットを実行するのとよく似ています。
location.assign("javascript:Grooveshark.playNextSong();void(0)");
ボーナススクリプト
上記の例を示す完全な Greasemonkey スクリプトを次に示します。このページで実行できます。
// ==UserScript==
// @name Content Function Test
// @namespace lwburk
// @include http://stackoverflow.com/questions/5006460/userscripts-greasemonkey-calling-a-websites-javascript-functions
// ==/UserScript==
function exec(fn) {
var script = document.createElement('script');
script.setAttribute("type", "application/javascript");
script.textContent = '(' + fn + ')();';
document.body.appendChild(script); // run the script
document.body.removeChild(script); // clean up
}
window.addEventListener("load", function() {
// script injection
exec(function() {
// alerts true if you're registered with Stack Overflow
alert('registered? ' + isRegistered);
});
// location hack
location.assign("javascript:alert('registered? ' + isRegistered);void(0)");
}, false);