Tyler Close, Mark Miller, and Marc Seaborn of Google have recently submitted their Powerbox proposal to the Device APIs & Policy WG. It defines a mechanism for exposing services (“Providers”) that may be local or remote, and may have privacy and security implications, to scripts running in a given page (“Customers”). In order to help develop, digest, and bind it to concrete technology this note walks through the development and deployment of a Powerbox-enabled service, discussing some gaps along the way.

Before You Read More

I made this document because I started off with an email but it became too long and messy. So I put the mess and length here. It is windy, makes side notes about things to change with the original proposal, makes no sense if you don't have the Powerbox document at hand, and is about as well organised as my mental capacities generally are. You have been warned.

Note on the Trusted Case

This document only concerns itself with the untrusted Web case. That approach was not taken with the intent to disregard the trusted case (e.g. widget, extension, etc.) but simply because given a Powerbox-compliant system, the trusted application case can be handled with two simple additions:

This minimal variation in the handling of the trusted case is seen as a bonus. Additional security models may be built largely by controlling which Providers are made available by default.

This may or may not be exaggerated depending on what the inputs produce on activation. That's an aspect to keep in mind while designing these.

The Use Case

Cryptozoology is a science with a bright future and devout following. A vast number of creature-specific social websites have sprouted in which communities can share sightings, tips, organise events, and so on: Dahut Hunters, Unicorn Riders, Yeti Trainers, Werewolves & Villagers, Zero-Bug Browsers, etc.

All is fine and well for a while and cryptozoologists the world over happily exchange with one another. But there is a problem: it is not uncommon for several of the studied species to to appear at the same time and location (e.g. after 2am at an open-air mulled wine party) or to cross-breed (e.g. dahunicorns). Wishing to recount the multiple encounter, a budding cryptozoologist must load up multiple sites, enter the same information multiple times, etc. It's a pain and science suffers. Having heard of the wonders of Powerbox, the World Wide Watchers of Cryptids asks its Demonstration through Anecdotal Proof Working Group to come up with a solution so that contacts from friends' lists at various community sites can be accessed uniformly. It is expected to be modelled after the same API that allows access to the local address book so that one can text both fellow enthusiasts and that dumb ex who called you crazy in one go.

Setting Up the Provider

As explained by the Powerbox document, a Provider is linked to a website in the following manner from the various relevant sites:

<link rel='provider' href='/apis/crypto-contacts-provider' title='Contacts'/>

Based on that, an affordance similar to those used for RSS feeds is made available (oftentimes an icon in the location bar) with which the user can install the provider.

What is not described in the Powerbox proposal is how the link is created between that URI and the filtering that file select controls operate on providers. The example in the Powerbox proposal uses the same URI for the provider and the provision request, which may or may not be intentional. For simplicity I'll assume a level of indirection and have the link point to a provider description which itself gives the URI for the service. If preferred, it is possible to have a standard way of requesting applicability information from the provider URI directly instead.

The resource at /apis/crypto-contacts-provider is therefore a JSON entity of the following rough shape:

{
    name:         "Cryptid Contacts for “Unicorns Are Tasty”",
    description:  "Makes your list of UAT contacts easily available everywhere",
    author:       "Damian Archibald Hutt"
    email:        "d@hutt.org",
    site:         "http://unicorn-syrup.com/",
    license:      "http://unicorn-syrup.com/t+c",
    icon:         "http://unicorn-syrup.com/favicon.svg",
    version:      "0.1",
    service:      "http://unicorn-syrup.com/api/contacts",
    proposes:     ["application/json", "application/atom+xml"],
    exposes:      "http://cryptideas.org/contacts",
    params:       {
        apiKey: "c0edbeef"
    }
}

Most parameters provided here are straightforward and only intended to make a list of installed providers somehow palatable and more useful to end users when manipulated inside the UA. The interesting ones are:

key value
service The URI of the actual endpoint for the provision request.
proposes A list of media types (that may include wildcards) to be matched against the accept attribute.
exposes An identifier for the API that is being exposed. See below.
params An open set of parameters that the UA has to remember and include in following provision requests. This can be used to pass in a key that the user needs to have.

Resource Requisition

So most cryptozoologist websites have set up their provider installer as described above and most folks have installed them. We can now proceed with our “ChupacaBroadcast” web application with which one can notify friends of a sighting.

Here I introduce a slight variation on the original proposal (largely because I don't see how it is supposed to be matched otherwise):

<input type='file' accept='application/json' pattern='http://cryptideas.org/contacts' multiple='multiple'/>

Essentially here, the accept attribute matches one of our proposes options, and the pattern attribute matches the exposes option. Reusing pattern here may be a bit tricky, but I feel that it is better than class in that it matches the intent somewhat more clearly, and HTML5 currently forbids pattern here so it's up for grabs.

Resource Provision

Let's assume that we have a user who belongs to both the “Dahut Circle” and the “Unique Horns” websites, for both of which he's installed the providers, and who wishes to share his snapshot of a dahunicorn. He opens up ChupacaBroadcast and activates the above input control. The UA pops up a list of all providers that support returning that media type for that API identifier which includes amongst others the two cited above plus the local contact store (our user is running the famous Zero-Bug Browser, which naturally exposes cryptid APIs).

First of all, does the multiple mean that the user can select several providers at once, or is that always/never the case? Or is the idea that that's something that the service should have to take into account so as to return a URI that exposes a single object (whatever that means, HTTP-wise)?

I'm going to assume here that it means the user can select multiple providers at once as it seems to be the most useful (where useful is "what jumps first to me mind") thing. Having selected “Dahut Circle”, “Unique Horns”, and “Local”, and okayed the dialog, a provision request is sent to all three services with the following parameters (departing slightly from the proposal):

accept
sent using the Accept header
lang
the value of the lang attribute on the element or its closest ancestor, if any
version
the version field of the provider description
api
the exposes field of the provider description
params
all the params from the provider description as JSON [Note: the whole request could perhaps use JSON instead of application/x-www-form-urlencoded]
data-*
all data-* attributes present on the element

For obvious reasons of privacy granularity, we do not want the providers to have as their sole choice to expose either all of the user's contacts or none. As such they do not yet return a provision response with a Location header that would provide the actual data (though if we did want an API providing all of the contacts they certainly could). Instead, the provision responses use the code 300 Multiple Choices and has an entity body (of course they may also return error codes).

For each provider the user is now presented with the return body. One way of doing this would be to have the provider choice dialog stay open and have its content replaced with the bodies, each in a different tab. The body can be anything that the browser understands, and its content is naturally unavailable to the original page. In our case each of them presents the user with a list of their contacts from which they can select several, all, or none. These bodies can interact with the provider as much as they want using regular HTTP (so that for instance they could also implement complex multipage wizards) but the first response that returns 201 Created with a defined Location header will cause that body (its tab if there are several, the dialog if it was the last one) to close.

Once the user has picked all of his contacts, the provided resources specified by the three services. Since we have more than one, we cannot use the value getter but must mint a new one similar to that used in the File API: provisions (name eminently changeable). [Note that this does not prevent inclusion in form submission.]

Scripting

The user then writes his message and okays it, which causes the following code to run (assuming jQuery for brevity):

function tellEveryone () {
    var contacts = [], received = 0;
    var provs = $("#myInput")[0].provisions;
    for (var i = 0, n = provs.length; i < n; i++) {
        $.getJSON(provs[i], function (data) {
            $.each(data.contacts, function (i, it) { contacts.push(it); });
            received++;
            if (received == n) sendMessage({
                to:       contacts,
                subject:  "A dahunicorn!",
                body:     "HA! Who's crazy NOW!?"
            });
        });
    }
}

And that's it!

Next Steps

The original proposal had an interesting video example, and this one does a very simple contacts selection. What I'd be interested finding out is whether this scales nicely to more complex protocols, including full CRUD, as well as as double-checking that we can make this work simply in trusted environments.