Can JQuery be used by a multiprocess Firefox extension?

186 Views Asked by At

The Mozilla documentation is silent on this issue. Is there anyone in the know that can answer and explain why or why not? If not, I'd like to know the policy reasons and architectural decisions why not.

Edit: This question is limited to extensions that cannot use the Add-on SDK and instead use the traditional overlay pattern.

2

There are 2 best solutions below

3
On

Framescripts are not webpages and do not offer access to most of the global variables that jquery expects to exist, e.g. XHR, the document and window itself etc.

Even if you rigged the variables in a way that looks like a window environment this would still be highly problematic because a frame script has a lifetime that extends beyond that of a DOM windows, i.e. its existence is tied to a tab, not to individual pages of a tab. Jquery is designed to only live as long as a page does.

A third problem is security, framescripts run with chrome/system privileges and so would jquery if you ran it directly from a frame script. Jquery is not designed to be security-conscious as it is normally constrained by the same-origin policy of a website. Some complex interaction of event processing and XHRs might thus open security vulnerabilities.

So using jquery in browser-internal scripting environments is not recommended.

The two options of doing DOM manipulation from frame scripts is

a) Using standard DOM APIs directly from a frame script. Addon scripts automatically run with ES6 support enabled (e.g. destructuring, arrow functions etc.) and do not have to concern themselves with cross-browser compatibility. In other words: There's no need for jquery

b) If using jquery is absolutely necessary, e.g. because some 3rd-party library depends on it, then it's possible to create a sandbox with the current window as its prototype and using the subscript loader to inject jquery and a custom script into it.

Recommended way to create sandbox to isolate it from untrusted content and at the same time drop system privileges:

let options = {
  // this is the name reported in about:memory
  sandboxName: "<addon name> <purpose of sandbox>",

  // ensure that jquery sees the window as global
  sandboxPrototype: content,

  // reduces GC overhead by having the sandbox reside in the same space as target window
  sameZoneAs: content,

  // don't include components object that grants access to privileged APIs
  wantComponents: false, 

  // helper functions for interacting with untrusted content
  wantExportHelpers: true,

  // clean view of DOM APIs, otherwise untrusted content could override prototypes
  wantXrays: true,

  // addon ID, used by addon debugger and memory reporting
  // sdk addons can obtain it via require("sdk/self").id, other addons define it in the install.rdf
  metadata: {addonID: id}
}

// set the security principal to an extended principal covering the target window
let sandbox = Cu.Sandbox([content], options)

// structured-clone objects into the sandbox
sandbox.myData = {foo: "bar"}

loader.loadSubscript("resource://myaddon-id/libs/jquery.js", sandbox, "UTF-8")
loader.loadSubscript("resource://myaddon-id/src/mypagescript.js", sandbox, "UTF-8")

// call custom function created by mypagescript.js
sandbox.myFunc()

Note that the sandbox is only valid for the lifetime of a page, so if the frame gets navigated to a new window (content object) you will have to create a new sandbox


The above basically is the underlying low-level API used by the SDK's page-mod and webextensions content-scripts.

0
On

See my comments to your OP. The docs you read are not about content scripts. It is about framescripts and other elevated scopes. Google chrome does not have these elevated scopes. They ONLY have content script. This is why we were all confused.

This is how you use jQuery in your content scripts with jpm addon sdk.

Download the jquery lib into your data folder.

var tabs = require("sdk/tabs");
var mod = require("sdk/page-mod");
var self = require("sdk/self");

var pageUrl = self.data.url("page.html")

var pageMod = mod.PageMod({
  include: '*',
  contentScript: [self.data.url('jquery.min.js'), "console.log(jQuery);"]
})

This inserts jQuery into all websites. tabs.open(pageUrl);

If you use webextensions its the same exact way as google chrome: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/