要启动Firefox最简单的方式,推动第三方网站使用特权NSI *的API(Simplest way

2019-08-04 19:34发布

什么是启动Firefox最简单的方式,加载第三方网站(这我授权为“自动”),并运行针对该网站的一些“特权”的API? (例如:nsIProgressListener,nsIWindowMediator等)。

我已经尝试了两种方法:

  1. 创建使用的XULrunner选项卡式浏览器,“管道”所有的第三方网站,打开新窗口,遵循302个重定向等所需的合适的API这样做,这样,它是一个aweful大量的代码,并要求(AFAICT)表示,用户安装的应用程序,或者运行火狐-app。 这也是极其脆弱。 : - /

  2. 启动Firefox使第三方网站的网址,与MozRepl已在侦听。 然后启动后不久,从“启动”脚本MozRepl telnet使用mozIJSSubScriptLoader :: loadSubScript加载我的代码,然后在第三方网站的情况下,从MozRepl执行我的代码- 这是目前我做的方式它

与第一种方法,我得到很多的安全问题(明显)来解决,而且好像我写10倍以上的浏览器“管道”代码,然后自动化代码。

在第二种方法中,我看到很多的“时间问题”,即:

  • 所述第三方网站以某种方式从装载由MozRepl防止(或特权代码的执行我公司供应)???,或
  • 第三方网站的加载,但代码通过MozRepl执行不看到它加载,或
  • 第三方网站加载,和MozRepl不准备采取请求(尽管其他JavaScript在网页上运行,并且端口4242通过Firefox进程的约束)
  • 等等

我想过,也许做这样的事情:

修改MozRepl源以某种方式从在启动文件系统可预测的地方加载JavaScript的特权(或使用Firefox的命令行参数进行交互),并在第三方网站的上下文中执行它。

...甚至写另一个类似的附加哪个更专注于任务。

任何简单的想法?


更新:

大量的试验和错误后,回答我自己的问题(下)。

Answer 1:

我发现最简单的方法是写一个特制的Firefox扩展!

第1步。我不想做了一堆不必要的XUL /插件相关的东西,这是没有必要的; A“自举”(或重新startless)扩展仅需要一个install.rdf文件,以确定该附加组件,和一个bootstrap.js文件以实现自举接口。

  • 自举扩展: https://developer.mozilla.org/en-US/docs/Extensions/Bootstrapped_extensions

  • 很好的例子: http://blog.fpmurphy.com/2011/02/firefox-4-restartless-add-ons.html

引导程序接口,可以非常简单地实现:

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.rdfbootstrap.js到一个新的zip文件的顶层,并重新命名的zip文件扩展名.xpi

步骤2.要对生产和测试可重复的环境,我发现最简单的方法是用一个专用的自动化任务的配置文件启动Firefox:

  • 启动Firefox的配置文件管理器: firefox -ProfileManager
  • 创建一个新的配置文件,指定容易再利用的 (我打电话给我testing-profile ),然后退出文件管理器。
  • 取下新轮廓profiles.ini在用户的Mozilla浏览器配置(这样不会妨碍正常浏览的干扰)。
  • 启动Firefox与简介: firefox -profile /path/to/testing-profile
  • 从安装文件系统(而不是addons.mozilla.org)延伸。
  • 做别的准备文件所需。 (例如:我需要添加第三方证书,并允许弹出窗口的相关领域。)
  • 留下一个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在每次启动。

注:我发现我不得不移动/PATH/TO/EXTERNAL/文件夹上面的步骤2中的其他地方,作为外部JavaScript代码将被缓存-轮廓内(!!!发展过程中不良)(即:更改外部代码不会被视为在下次启动)。

外部代码是特权,并且可以使用任何Mozilla平台的API。 然而,有的问题。 在其中外部代码被包括(并且因此执行)的时刻,在时间是一个在其中没有铬窗口对象(和因此没有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.$;
}

现在我们可以使用jQuery任何DOMWindow通过传递<DOMWindow>.document作为第二个参数来选择呼叫!



文章来源: Simplest way to launch Firefox, drive 3rd party site using privileged nsI* APIs