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.
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:
<input type="file"/>elements that can be activated in script.
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.
input
s produce on activation. That's
an aspect to keep in mind while designing these.
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.
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. |
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.
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
headerlang
attribute on the element or its closest ancestor, if anyversion
field of the provider descriptionexposes
field of the provider descriptionapplication/x-www-form-urlencoded
]
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.]
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!
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.