Labs/Jetpack/Reboot/JEP/106

From MozillaWiki
< Labs‎ | Jetpack‎ | Reboot‎ | JEP
Revision as of 22:49, 9 April 2010 by Warner (talk | contribs) (update with current plan)
Jump to navigation Jump to search

JEP 106 - Registered Jetpack URLs

  • Champion: Atul Varma - avarma@mozilla.com
  • Status: Accepted/Pre-Production
  • Bug Ticket: bug 549319
  • Type: API


Problem Statement

Every file in a Jetpack package needs a unique identifier for a variety of reasons:

  • If an error occurs in a Jetpack's code, the traceback needs to include a URL that doesn't give away potentially sensitive information about its location on the user's filesystem.
  • If a Jetpack wants to embed one of its images in a web page, it probably needs to do so with a URL, although such could also be done with a data: URI.
  • If a Jetpack wants to self-host a web-like UI, it needs a URL to display in the URL bar. This URL should preferably be memorable but doesn't need to be.
  • If a Jetpack wants to process the data contained in a file in its package, it should do so via a URL (though a relative path can potentially be used).

A prerequisite for this is that each Jetpack must have a unique ID that cannot be spoofed. This is valuable for a number of reasons:

  • The host environment needs a way to keep track of Jetpack-specific resources; thus each Jetpack needs a primary key. If a Jetpack is uninstalled and reinstalled later and the user wants to keep their data, then the primary key may need to be preserved.
  • The host environment needs a way of telling that one Jetpack is an upgrade for another, while guaranteeing that the upgrade isn't a forgery.

Proposal

Jetpacks are accessible through the jetpack: protocol. Each Jetpack has a keypair associated with it, and a Jetpack's ID is the SHA-1 hash of its public key. Jetpacks must be signed using their private key, and will not be loaded unless signed; thus a Jetpack ID, if present in the system, is guaranteed to be unforgeable.

Use-Cases

  • The wants to display an image/resource/L10n bundled with a Jetpack - option for allowing exposure of resource location needs consideration
  • Developer debugging ergonomics
  • Dynamically created, cache enabled, resources

Key Issues

There are a number of security issues involved in this.

  • Jetpacks should have a way of specifying which of their resources is "private", i.e. accessible only by itself, vs. "public", i.e. accessible from external code like web pages.
  • It shouldn't be possible for a Jetpack to "spoof" another by e.g. having the same ID.
  • The security policy for HTML code needs to be well-defined; should it follow the Web's standard single-origin policy, or something else? Can scripts be loaded from remote pages?

Dependencies & Requirements

Internal Methods

API Methods

Discussion

My thoughts (developed during a discussion with Atul last week):

  • A "jetpack ID" should be the hash of a public verifying key. "jpx create-new-addon" will create a keypair, store the private signing key under ~/.jetpack/, and create a new skeleton add-on directory (with the public key and a manifest, and maybe a hello-world sample).
  • There will be a "jpx publish" command which bundles the various files together, signs the bundle, and drops the signed result in a well-known place, perhaps with an option to upload it to AMO
  • The main purpose of the signed bundle is to convince the add-on manager/loader to grant the new code the same authorities that were granted to its predecessor. In particular, any data stored by one version of an add-on should be available to the update too.
  • A well-known subdirectory of the add-on, perhaps ADDONBASE/resources/, should be used for "bundled resources". These are copied verbatim into the addon bundle.
  • Content frames (as described in JEP-115) should have easy access to bundled resources. In particular, creating such a frame with a URL of "/panel.html" should populate the frame with the contents of ADDONBASE/resources/panel.html , and relative URLs inside it should reference bundled resources too.
  • There should be a simple call that lets add-on code access the contents of bundled resources (from code, as opposed to from HTML), like:
var resources = require("bundled-resources");
var data = resources.load("panel.html")
  • These bundled resources are, in general, *not* available from outside the add-on. However, I think it could be useful to add a "publish" feature, such that an add-on could do something like:
var publisher = require("publisher");
publisher.publish("/foo.txt", function (req) { return "foo!" });

and then the rest of the browser could do a GET of jetpack://id/$JETPACKID/foo.txt and be given "foo!". The use of $JETPACKID here would be unforgeable.

  • When an exception occurs and we need put a "filename" property onto the exception object, we can use jetpack://$JETPACKID/jsfilename for debugging purposes. It would not necessarily be possible to paste this into the addressbar and see the source code in question, though (this sounds useful, but I think it's also important to allow add-ons to keep their resources private, so maybe only allow this to work in a debug console of some sort). It might be best for these URLs to have a different protocol, maybe jetpack-exception://, to distinguish it from the URLs managed by the "publisher" feature.

--Brian Warner 06:28, 16 February 2010 (UTC)

Our current plan:

  • The Jetpack ID will be made available to add-ons through the "self" package:
   var my_id = require("self").id;
  • The add-on package's `data` directory will contain the bundled resources. So if the main add-on code lives in PKGROOT/lib/main.js , a typical resource would live in PKGROOT/data/icon.png
  • The "self" package has a `data` property which provides access to these resources:
   var data = require("self").data;
   var text = data.load("foo.txt"); // contents of PKGROOT/data/foo.txt
   var icon_url = data.url("icon.png");
  • The URL method will return a URL instance that can be used to load the given resource. This URL can only be used by content frames opened by the same package which provided the resource: it does not provide a way for add-ons to publish data to anyone else (we'll offer some other mechanism for that in the future).
  • We expect the URL to look like `resource://jetpack/$JID/main.html`, but the actual syntax is opaque and private: add-on code should not depend upon the details. The only promise made by `data.url()` is that relative links should work correctly: PKGROOT/data/page.html can reference PKGROOT/data/image.png with a normal `<img src="image.png"/>` tag.
  • An NSIContentPolicy object will be used to enforce the non-sharedness of these resource URLs. This may not be enforced right away, but eventually it will.

--Brian Warner 22:49, 9 April 2010 (UTC)