gpt4 book ai didi

javascript - 启动 Firefox、使用特权 nsI* API 驱动第 3 方站点的最简单方法

转载 作者:行者123 更新时间:2023-11-29 22:17:53 26 4
gpt4 key购买 nike

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

我尝试了两种方法:

  1. 使用 XULrunner 创建一个选项卡式浏览器,“连接”第 3 方站点打开新窗口所需的所有适当 API,遵循 302 重定向等。这样做,代码量非常大,而且要求(afaict)用户安装该应用程序,或使用 -app 运行 Firefox。它也非常脆弱。 :-/

  2. 启动 Firefox 传递第 3 方站点的 URL,MozRepl 已经在监听。然后在启动后不久,从“启动”脚本远程登录到 MozRepl,使用 mozIJSSubScriptLoader::loadSubScript 加载我的代码,然后在第 3 方站点的上下文中从 MozRepl 执行我的代码——这就是我的方式我正在做这件事

使用第一种方法,我遇到了很多安全问题(显然)需要解决,而且我编写的浏览器“管道”代码似乎是自动化代码的 10 倍。

使用第二种方法,我看到很多“时间问题”,即:

  • MozRepl(或我提供的特权代码的执行)以某种方式阻止了第 3 方站点的加载???,或
  • 第 3 方站点加载,但 MozRepl 执行的代码看不到它加载,或者
  • 第 3 方站点加载,MozRepl 尚未准备好接受请求(尽管页面中运行其他 JavaScript,并且端口 4242 被 Firefox 进程绑定(bind)),
  • 等等

我想也许可以做这样的事情:

以某种方式修改 MozRepl 源代码以在启动时从文件系统中的可预测位置加载特权 JavaScript(或与 Firefox 命令行参数交互)并在第 3 方网站的上下文中执行它。

...甚至编写另一个更专注于该任务的类似插件。

有什么更简单的想法吗?


更新:

经过大量的反复试验,回答了我自己的问题(如下)。

最佳答案

我发现最简单的方法是编写一个专门构建的 Firefox 扩展!

第 1 步。 我不想做一堆不必要的 XUL/插件相关的事情; “自举”(或重新启动)扩展只需要 install.rdf用于识别插件的文件,以及一个 bootstrap.js文件来实现引导接口(interface)。

引导接口(interface)可以非常简单地实现:

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 来编译扩展和 bootstrap.js进入新 zip 文件的顶层,并将 zip 文件扩展名重命名为 .xpi .

第 2 步。 要为生产和测试提供可重复的环境,我发现最简单的方法是使用专用于自动化任务的配置文件启动 Firefox:

  • 启动 Firefox 配置文件管理器:firefox -ProfileManager
  • 创建一个新的配置文件,指定位置以便于重复使用(我调用我的 testing-profile ),然后退出配置文件管理器。
  • profiles.ini 中删除新配置文件在您用户的 mozilla 配置中(这样它就不会干扰正常浏览)。
  • 使用该配置文件启动 Firefox:firefox -profile /path/to/testing-profile
  • 从文件系统(而不是 addons.mozilla.org)安装扩展。
  • 做准备个人资料所需的任何其他事情。 (例如:我需要添加第 3 方证书并允许相关域的弹出窗口。)
  • 留单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 步。 现在,当我使用 testing-profile 启动 Firefox 时它将“包含”位于 /PATH/TO/EXTERNAL/CODE.js 的外部代码在每次启动时。

注意:我发现我必须移动 /PATH/TO/EXTERNAL/在上面的步骤 2 中其他地方的文件夹,因为外部 JavaScript 代码将被缓存(!!! - 在开发过程中不可取)在配置文件中(即:对外部代码的更改将在下次发射时可以看到)。

外部代码享有特权,可以使用任何 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.$;
}

现在我们可以使用jQuery在任何 DOMWindow通过 <DOMWindow>.document作为选择器调用的第二个参数!

关于javascript - 启动 Firefox、使用特权 nsI* API 驱动第 3 方站点的最简单方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14055646/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com