2

Firefoxを起動し、サードパーティのWebサイト(「自動化」する権限があります)をロードし、そのサイトに対していくつかの「特権」APIを実行する最も簡単な方法は何ですか?(例:nsIProgressListener、nsIWindowMediatorなど)。

私は2つのアプローチを試しました:

  1. XULrunnerを使用してタブ付きブラウザを作成し、サードパーティのサイトが新しいウィンドウを開いたり、302リダイレクトをフォローしたりするために必要なすべての適切なAPIを「配管」します。このようにすると、非常に多くのコードが必要になります。ユーザーがアプリをインストールするか、-appを使用してFirefoxを実行します。また、非常に壊れやすいです。:-/

  2. MozReplがすでにリッスンしている状態で、サードパーティサイトのURLを渡すFirefoxを起動します。次に、起動後すぐに、「launch」スクリプトからMozReplにTelnetで接続し、mozIJSSubScriptLoader :: loadSubScriptを使用してコードをロードし、サードパーティサイトのコンテキストでMozReplからコードを実行します。これが現在の方法です。それ

最初のアプローチでは、(明らかに)多くのセキュリティ問題を回避する必要があり、自動化コードよりも10倍多くのブラウザ「配管」コードを書いているようです。

2番目のアプローチでは、多くの「タイミングの問題」が発生しています。

  • サードパーティのサイトは、MozRepl(または私が提供する特権コードの実行)によってロードされないようになっています???、または
  • サードパーティのサイトは読み込まれますが、MozReplによって実行されたコードは読み込まれません。
  • サードパーティのサイトが読み込まれ、MozReplがリクエストを受け取る準備ができていません(ページで他のJavaScriptが実行されていて、ポート4242がFirefoxプロセスにバインドされているにもかかわらず)。

私は多分このようなことをすることを考えました:

何らかの方法でMozReplソースを変更して、起動時にファイルシステムの予測可能な場所から特権JavaScriptをロードし(またはFirefoxコマンドライン引数と対話し)、サードパーティのWebサイトのコンテキストで実行します。

...または、タスク専用の別の同様のアドオンを作成することもできます。

もっと簡単なアイデアはありますか?


アップデート:

試行錯誤の末、私自身の質問に答えました(下記)。

4

1 に答える 1

2

最も簡単な方法は、専用のFirefox拡張機能を作成することでした。

ステップ1.不要なXUL/アドオン関連のものをたくさんやりたくありませんでした。「ブートストラップ」(または再起動なし)拡張機能にはinstall.rdf、アドオンを識別するためのbootstrap.jsファイルと、ブートストラップインターフェイスを実装するためのファイルのみが必要です。

ブートストラップインターフェイスは非常に簡単に実装できます。

const path = '/PATH/TO/EXTERNAL/CODE.js';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
var loaderSvc = Cc["@mozilla.org/moz/jssubscript-loader;1"];
                    .getService(Ci.mozIJSSubScriptLoader);

function install() {}
function uninstall() {}
function shutdown(data, reason) {}
function startup(data, reason) { loaderSvc.loadSubScript("file://"+path); }

install.rdfを新しいzipファイルのトップレベルに配置して拡張子をコンパイルしbootstrap.js、zipファイル拡張子の名前をに変更します.xpi

ステップ2.本番環境とテスト環境を再現できるようにするために、自動化タスク専用のプロファイルを使用してFirefoxを起動するのが最も簡単な方法であることがわかりました。

  • Firefoxプロファイルマネージャーを起動します。firefox -ProfileManager
  • 新しいプロファイルを作成し、簡単に再利用できる場所testing-profileを指定して(私は私のものと呼びます)、プロファイルマネージャーを終了します。
  • ユーザーのmozilla構成から新しいプロファイルを削除profiles.iniします(通常のブラウジングに干渉しないようにするため)。
  • そのプロファイルでFirefoxを起動します。firefox -profile /path/to/testing-profile
  • (addons.mozilla.orgではなく)ファイルシステムから拡張機能をインストールします。
  • プロファイルを準備するために必要な他のことを行います。(例:サードパーティの証明書を追加し、関連するドメインのポップアップウィンドウを許可する必要がありました。)
  • 1つのabout:blankタブを開いたままにして、Firefoxを終了します。
  • プロファイルのスナップショット:tar cvf testing-profile-snapshot.tar /path/to/testing-profile

その時点から、自動化を実行するたびにtesting-profile-snapshot.tar、既存のtesting-profileフォルダーを解凍しfirefox -profile /path/to/testing-profile about:blank、「元の」プロファイルを使用するように実行します。

ステップ3.Firefoxを使用して起動すると、起動するたびtesting-profileに外部コードが「含まれる」ようになります。/PATH/TO/EXTERNAL/CODE.js

注:外部JavaScriptコードがプロファイル内にキャッシュされるため(つまり、開発中に望ましくない)、外部コードへの変更が表示されないため、上記の手順2/PATH/TO/EXTERNAL/フォルダーを別の場所に移動する必要があることがわかりました。次回の起動時)。

外部コードには特権があり、MozillaプラットフォームAPIのいずれかを使用できます。ただし、タイミングの問題があります。外部コードが含まれている(したがって実行されている)瞬間は、ChromeウィンドウオブジェクトDOMWindowがまだ存在しない(したがってオブジェクトが存在しない)瞬間です。

DOMWindowしたがって、有用なオブジェクトが見つかるまで待つ必要があります。

// useful services.
Cu.import("resource://gre/modules/Services.jsm");    
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
                .getService(Ci.mozIJSSubScriptLoader);

var wmSvc = Cc["@mozilla.org/appshell/window-mediator;1"]
                .getService(Ci.nsIWindowMediator);

var logSvc = Cc["@mozilla.org/consoleservice;1"]
                .getService(Ci.nsIConsoleService);

// "user" code entry point.
function user_code() {   
   // your code here!
   // window, gBrowser, etc work as per MozRepl!
}

// get the gBrowser, first (about:blank) domWindow, 
// and set up common globals.
var done_startup = 0;
var windowListener;
function do_startup(win) {

    if (done_startup) return;
    done_startup = 1;
    wm.removeListener(windowListener);

    var browserEnum = wm.getEnumerator("navigator:browser");
    var browserWin = browserEnum.getNext();
    var tabbrowser = browserWin.gBrowser;
    var currentBrowser = tabbrowser.getBrowserAtIndex(0);
    var domWindow = currentBrowser.contentWindow;
    window = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIWebNavigation)
                 .QueryInterface(Ci.nsIDocShellTreeItem)
                 .rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIDOMWindow);
    gBrowser = window.gBrowser;

    setTimeout = window.setTimeout;
    setInterval = window.setInterval;
    alert = function(message) { 
        Services.prompt.alert(null, "alert", message); 
    };
    console = { 
        log: function(message) { 
            logSvc.logStringMessage(message); 
        } 
    };

    // the first domWindow will finish loading a little later than gBrowser...
    gBrowser.addEventListener('load', function() {
        gBrowser.removeEventListener('load', arguments.callee, true);
        user_code();
    }, true);
}

// window listener implementation
windowListener = {
    onWindowTitleChange: function(aWindow, aTitle) {},
    onCloseWindow:       function(aWindow) {},
    onOpenWindow:        function(aWindow) {
        var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
        win.addEventListener("load", function(aEvent) {
            win.removeEventListener("load", arguments.callee, false);
            if (aEvent.originalTarget.nodeName != "#document") return;
            do_startup();
        }
};

// CODE ENTRY POINT!
wm.addListener(windowListener);

ステップ4.そのコードはすべて「グローバル」スコープで実行されます。後で他のJavaScriptファイル(例:jQuery)をロードする必要がある場合は、 (グローバル!)スコープloadSubscript内で明示的に呼び出しますnull

function some_user_code() {
    loader.loadSubScript.call(null,"file:///PATH/TO/SOME/CODE.js");
    loader.loadSubScript.call(null,"http://HOST/PATH/TO/jquery.js");
    $ = jQuery = window.$;
}

これで、2番目のパラメーターとしてセレクター呼び出しに渡すことjQueryで、anyで使用できます。DOMWindow<DOMWindow>.document

于 2013-01-08T03:19:11.640 に答える