Analysis of provider API styles

18 views
Skip to first unread message

Mike Hanson

unread,
Aug 22, 2011, 3:57:17 PM8/22/11
to web-i...@googlegroups.com
Hi all - as we discussed in the last meetup, I've been circulating and discussing options for the provider's API.

As we left things at the end of the meetup, there was strong support for the window.intent approach from the Chrome team, but equally strong misgivings (from Tyler and me) that there was no secure way to include this using a JS API.  We had just started to mock up a safe API (something like #4, below) but we didn't get to something concrete.  I'm having a hard time getting any agreement on this side until we have something that can be on-boarded through an included JS API.

In the interest of moving things forward, here's my understanding of the options - I'm including Introducer, Tyler, since we talked about it during the last meetup.  

I know that the Chrome team had previously tried something like #4 and backed away from it.  Can you please give us an explanation of where you hit problems with that?  That would help us understand the tradeoffs with #1.


Style 1:
before page loads, window.intent is loaded with the intent object
if (window.intent) {
if (window.intent.action == SOME_ACTION) {
doWork(window.intent.data);
window.intent.postResult( ... );
}
}

Style 2:
use event listeners
document.addEventListener("onIntent", function(intent) {
if (intent.action == SOME_ACTION) {
doWork(intent.data);
intent.postResult( ... );
}
})

Style 3:
use a registration function, providing the action as input
window.registerIntentHandler(SOME_ACTION, function(intent) {
doWork(intent.data);
intent.postResult( ... );
});

Style 4:
register a single function
window.registerIntentHandler(function(intent) {
if (intent.action == SOME_ACTION) {
doWork(window.intent.data);
window.intent.postResult( ... );
}
});

Style 5:
use a registration function, passing a message port at call time
introducer.accept(function(port, intentList, origin) {
if (actionInIntentList(SOME_ACTION, intentList)) {
doWork(port.read());
...
port.write( ... );
}
});


Style 1:
+ Indicates clearly that the reason for this window is this intent
+ Unforgable if inserted by UA
+ Removes all racy-ness from API; all data is ready to go
+ Potentially very quick; intent could be satisfied on very first execute call
- Requires that intent data be assembled before window can execute (slow?)
- No clear indication that an intent is not supported; perhaps postError?
- No support for multi-step/back-and-forth interactions
- No way to reuse a single window for multiple calls; limits interactive use cases
-- Currently no safe way to do from a JS API

Style 2:
++ Very DOM-y and idiomatic for web programmers
- No clear indication that an intent is not supported; perhaps postError?
--- Insecure; can be spoofed from other pages on the same domain

Style 3:
+ Somewhat DOM-y and idiomatic for web programmers
+ Unforgable if inserted by UA
+ Has clear indication that an intent is supported
+ Can be safely injected from JS API
- Feels racy - UA is required to park the intent data and wait until it thinks it's safe to fire the intent - perhaps onload?

Style 4:
+ Perhaps a bit more DOM-y and idiomatic; feels like a special kind of addEventListener
+ Unforgable if inserted by UA
+ Can be safely injected from JS API
- No clear indication that an intent is not supported; perhaps postError?
- Somewhat less racy - can the UA fire as soon as it sees registerIntentHandler?  Probably not; it would be idiomatic to let the script execution terminate before we fire.

Style 5:
+ Intent can't be replayed
+ Port is a persistent connection which can be passed to other contexts and benefits from existing MessagePort implementations
+ Persistent bidirectional communication channel
- Intent can't be replayed (e.g. if authn is required)
- Requires building an RPC format abstraction on top of raw pipe; more moving parts, more complexity


Best,
Mike

Greg Billock

unread,
Aug 22, 2011, 6:57:08 PM8/22/11
to web-i...@googlegroups.com
I'll see if Paul Kinlan can join the group to talk about putting window.intent into the JS API. If we can't get it to work properly there, it is a negative for sure.

I think you've captured in the pros/cons most of the reasons we favored window.intent. Basically registerIntentHandler is more API surface area, whereas window.intent only shows up when you need it. The downside of that API surface is mostly raciness, as you note. That is, there's some caveats as to where you can/should utter that command which don't happen with window.intent. On the other side, having a clear consumption of the intent by those registrations is a positive thing -- the machinery can be sure that the intent is expected and being consumed.

The other thing as the potential collision because of repetitiveness (need to sync up manifest and registration for explicit intent handling). We at first confused ourselves between whether this register call would actually do the installation, but I don't think developers will experience that -- installation is clearly separated as it's documented now, whether by <intent> tag or by manifest, so I don't think that's as much an issue. For (4), that issue largely disappears (except for the problem we've discussed about when a particular handler stops being one), at the cost of a switch statement in the Javascript.

I agree that a JS library will be a great thing to have, but perhaps we don't have a good sense yet as to how important it'll be during adoption. If use of intents is really widespread very early, then publishers are going to need fallbacks for non-supporting browser versions. If on the other hand it tends to track HTML5 adoption and get deployed as an enhancement, it may not be as important. Perhaps Paul can comment on this.

While I think the way he's currently populating window.intent is faithful to the spec, I suspect there are other ways to do it that would introduce unfaithfulness to the spec, strictly speaking, but remove security problems. (i.e. sequencing of onload handlers so the shim handler comes first, which is technically not following the spec, but might be enough to get us through an adoption period and would continue to work fine without the shim.)

Paul Kinlan

unread,
Aug 26, 2011, 9:56:53 AM8/26/11
to web-i...@googlegroups.com
Currently window.intent is populated by encoding the data in window.name then removing it as soon as the intent library has parsed it.  I am presuming the security misgivings are primarily down to a script changing document.location prior to the webintents script loading?

The very first version of the shim didn't use this hack, rather it used MessagePorts (which FF and IE didn't support), then just used a plain postMessage to get the data from the webintents framework, however this had many problems 1) it required that we store user data in localStorage on the webintents domain and 2) it was impossible to get the window.intent data populated prior to onload ("onmessage" will not process messages until onload has occurred which means the host of the iframe also has received an onload and thus has no intent data).

There seems to be some confusion that registerhandler is doing two things, physically registering the intent AND also handling the invocation by the UA.  It was the reason why I liked an onIntent event listener because it separates both registration and the handling of the intent (or at least the assumption that register actually registers it in the system) and allows us to 

On the subject of the current JS shim API, because we need to populate window.intent prior to onload, we can't use script loaders like YepNope etc which in my opinion is a key requirement to getting developers to adopt this in their apps (if they need to support legacy browsers then they need to know when to load the shim).
--
Paul Kinlan
Developer Advocate @ Google for Chrome and HTML5
t: +447730517944
tw: @Paul_Kinlan
LinkedIn: http://uk.linkedin.com/in/paulkinlan
Blog: http://paul.kinlan.me
Skype: paul.kinlan

Tyler Close

unread,
Aug 26, 2011, 12:23:07 PM8/26/11
to web-i...@googlegroups.com
On Fri, Aug 26, 2011 at 6:56 AM, Paul Kinlan <paulk...@google.com> wrote:
> Currently window.intent is populated by encoding the data in window.name
> then removing it as soon as the intent library has parsed it.  I am
> presuming the security misgivings are primarily down to a script changing
> document.location prior to the webintents script loading?

There are a few issues with using window.name for cross-domain comms.
1) On IE7 and earlier, a page in any origin can read the window.name
of another window and so could snoop on intent data.
2) On any browser, a page could load a URL from its own origin in the
window and snoop on intent data.
3) On any browser, a page could load a URL for a provider other than
the selected one in the window and so make that provider believe that
the user selected it for the current intent.

All of this assume you've already implemented some scheme that enables
the selected provider to verify that the window.name data was set by
the trusted webintents origin. Without that, there are obviously many
additional problems. What technique are you using to verify that the
window.name data was set by the webintents origin?

--Tyler

Paul Kinlan

unread,
Aug 26, 2011, 12:58:52 PM8/26/11
to web-i...@googlegroups.com
This is one of the areas of the shim that still needs more work.  I have it on a branch of the shim to check that the opener is webintents.org but it is not yet merged in - I will raise an issue now.

P
Reply all
Reply to author
Forward
0 new messages