Monday, January 25, 2010

Extending Chrome and Firefox privileges with message passing.

I'm going off on a technical tangent for this post because I'd like to take the time to write a little about the design of our application platform, Kixx. Specifically, I'm going to outline how I think we can build privileged applications using the web browser as a platform. By privileged, I mean applications that can make cross domain network calls and have access to a local storage system among many other things that normal web pages cannot do.

The Firefox and Chrome web browsers both have some notion of a background page running with extended local privileges available to extension developers. For Firefox, this takes the form of an undocumented and hidden window running within the the core of the browser referred to as the "chrome" by Mozilla developers. In the Chrome browser, extension authors can explicitly load an HTML document (with JavaScript) into a background page using the manifest configuration of an installed extension.

We can build an extension for both the Chrome and Firefox browsers that takes advantage of these features to give extended privileges to pages running in the normal browser window tabs. This way, we can build locally installed applications which run in the browser and can do things like make cross domain XMLHttpRequest Ajax calls, open new browser tabs, and do other stuff that web pages should not normally be allowed to do.

Firefox extension developers are able to make actual JavaScript objects available to content pages from the internal JavaScript of the browser. On the other hand, Chrome extension developers must create a message passing API between the privileged extension scripts and the DOM of the content page.

For security reasons, and because of the Chrome browser design for page interaction, our design will be using a message passing API. There are also some other side benefits of the message passing design that I'll mention later.

In the Firefox extension, we will dynamically place an iframe element into the hidden window from the JavaScript in our extension. We'll then load our own page, which implements the privileged half of our message passing API, within our iframe element as the browser loads.

In the Chrome extension our message passing API will be implemented in a simple background page. We'll be able to use a content script explicitly declared in the extension manifest to facilitate communication with normal content pages.

In both browsers, this scheme will look something like fig 1.

The "privileged execution frame" in fig 1 is the background page we loaded from our browser extension. The "bridge API script" is the script running in that page which implements the privileged side of our message passing system.

The "content execution frame" contains the normal tabbed browsing pages.

However, for good reason, we do not want to give any web page that the user loads into the browser these extended privileges. We only want certain pages that we designate to be able to have access to our message passing API.

To accomplish this, we'll set up a folder somewhere on the local file system to contain our privileged applications. We'll call these mini applications toolpacks. Only pages loaded using the file:// URL scheme from our toolpacks will have access to our message passing API.

The design for our toolpacks will look something like fig 2.

Each toolpack exists in its own folder on the local file system. A toolpack may consist of HTML pages, JavaScript files, CSS, and images. One toolpack will contain the JavaScript file for the non-privileged side of our message passing bridge API (shown in the red in fig 2). As shown in fig 3, toolpacks can access the message passing API by importing it using a script tag in an HTML file. When a toolpack is loaded from a file:// URL that contains a reference to the messaging passing bridge script via a script src="..." tag, the toolpack can use only the privileges given to it by the message passing API. Further, no pages loaded from any other URL scheme (ie. from the Web) will be given the message passing API, even if it tries to load it. There are some additional benefits of the message passing design besides just security (that I promised to talk about earlier). First, we can poach the basic API design from the web worker scheme being specified by the WHATWG clan. Second, the message passing design allows for better concurrent processes within complex applications, sort of like Erlang. As far as I know, this scheme will only work for the Chrome and Firefox web browsers because of their capability to run background pages. To support other browsers we'll probably have to learn some different tricks. So, anyway, that is the basic idea of the design. I'll talk about API design and implementation ideas in later posts.

1 comment:

  1. The hidden background page feature you mentioned for Firefox is not undocumented, it is a fully supported API called Page Worker provided by the Add-ons SDK: https://jetpack.mozillalabs.com/sdk/1.0b2/docs/#module/addon-kit/page-worker

    ReplyDelete