W3C home > Mailing lists > Public > public-device-apis@w3.org > June 2010

Re: API patterns and requirements

From: Wojciech Masłowski <wmaslowski@opera.com>
Date: Fri, 18 Jun 2010 17:06:33 +0200
Message-ID: <4C1B8B79.9080809@opera.com>
To: Rich Tibbett <rich.tibbett@gmail.com>
CC: public-device-apis@w3.org
W dniu 2010-06-18 14:40, Rich Tibbett pisze:
> 2010/6/18 Wojciech Masłowski <wmaslowski@opera.com 
> <mailto:wmaslowski@opera.com>>
>
>     W dniu 2010-06-17 16:23, Rich Tibbett pisze:
>>     I've been thinking about the general interface patterns that we
>>     are using in the some of the APIs, particularly with a focus on
>>     Contacts and System-Info.
>>
>>     On the one hand there is a requirement that API calls be
>>     asynchronous. On the other hand, in order to ensure a reasonable
>>     user experience (i.e. don't bombard the user with more than one
>>     permission request at a time) I think we should include a
>>     requirement for serial access to each API (or collectively, all
>>     APIs) - that no more than one API call should be executable
>>     concurrently. I'd like to explore if this is a reasonable
>>     assumption for e.g. Contacts and whether any changes to the
>>     pattern used may be required for this.
>>     /_
>>     _/
>
> /[original code snipped]/
>
>>     /__/
>     I don't really think that mandating that only one call is going to
>     help with a problem of annoying user with security requests in any
>     way.
>
>
> Security requests may be unavoidable where we don't have any 
> pre-defined trust relationships. This proposal does not remove the 
> need for security requests but only ensures that a web app cannot 
> bombard the user with those security requests.
>
>     Consider the following use case: web app wants to get power and
>     network info. With your suggested solution it would look like that.
>
>     navigator.system.request.onsuccess = function() {
>         doSomethingWithBatteries(navigator.system.request.result);
>         navigator.system.request.onsuccess = function() {
>             doSomethingWithNetworks(navigator.system.request.result);
>         };
>         navigator.system.get('Network'); // triggers 2nd permission
>     request
>     };
>     navigator.system.request.onerror = function() {
>         // even if we don't get access to Power we want to try to get
>     Network info
>
>         navigator.system.request.onsuccess = function() {
>             doSomethingWithNetworks(navigator.system.request.result);
>         };
>         navigator.system.get('Network'); // triggers 2nd permission
>     request
>     };
>     navigator.system.get('Power'); // triggers 1st permission request
>
>     If we allow concurrent request the code looks like this
>
>     navigator.system.get('Power', doSomethingWithBatteries ); //
>     triggers 1st permission request
>     navigator.system.get('Network' doSomethingWithNetworks); //
>     triggers 2nd permission request
>
>     In both examples the user will be asked for permission twice. The
>     first one is much more complicated.
>
>
> It looks a little more complex but the application is presenting a 
> clearer interaction flow in the first example than in the second. 
> Developers actually have to design their web application from a user 
> interaction perspective in the first snippet: each nested API call 
> probably requires a subsequent security request and the pattern 
> requires the developer to plan that appropriately (and limit the 
> number of permission requests being called). So I actually still 
> prefer the first example. The second example could also generate race 
> conditions if we're not careful (e.g. if the web app requires that 
> 'Power' completes before examining 'Network' but 'Network' returns 
> first).
>
> Using the second example, if a web application executes 1000 API calls 
> up front would the user will be presented with 1000 security dialogs? 
> The proposal would mitigate such malicious usage of Device APIs.
I think most browsers will serialize security dialogs anyway - ie. you 
wont get next security dialog until you answer the first. And probably 
the dialog won't be modal but some non-intrusive notification, for 
example a bar on top of the page saying "This page wants to access your 
contacts. Allow/Deny". The  If the malicious script tried to spam user 
with security dialogs he would just ignore it. My point is that we might 
be solving a non-existing problem here.
>
>
>     Additionally with your solution we have to specify what happens in
>     this case :
>
>     navigator.system.request.onsuccess = fun1
>     navigator.system.get('Network');
>     navigator.system.request.onsuccess = fun2
>
>     will fun1 be called or fun2?
>
>
> fun2 would be called. Just like any other ECMAScript 
> variable, navigator.system.request.onsuccess has been overwritten with 
> a new value in the snippet above.
Well in that case lets consider following piece of code
Thread1:
     navigator.system.request.onsuccess = handleGetNetwork
     navigator.system.get('Network');
Thread2:
     navigator.system.request.onsuccess = handleGetPower
     navigator.system.get('Power');

lets say the code in thread1 got executed first and in thread2 second 
(as first get was being executed it failed immediately) and then first 
get finishes - What we get is handleGetPower called after getting 
network. Such race conditions can of course be avoided by developer but 
it is anther pitfall which is avoided by just passing callbacks to the 
function.
>
>>     This pattern provides two additional benefits over the current APIs:
>>
>>     1. only one async method (e.g. in the Contacts API this includes
>>     find(), save() and remove()) can be requested at any one time
>>     (i.e. serial access only).
>     I don't see how mandating only one async call gives advantage over
>     possibility of many concurrent calls. In both cases developer will
>     spam user with permission requests if he requests data too often.
>
>
> I see the following advantages of serializing access to API calls.
>
> - it throttles the user interaction (e.g. security/permissions opt-in) 
> required with the app. A malicious app cannot send 10000 requests to a 
> Device API.
As I said above, unless the dialogs are intrusive then this problem 
solves itself by user just ignoring them.
> - Developers are required to plan their 
> applications intelligently around a clear Device API access flow.
I don't see how that relates to device api access flow. In both cases I 
think being asynchronous is enough for the api to match access flow.
> - Race conditions are removed (e.g. performing a 'save contact 
> process' while performing a 'find contacts process' could result in 
> such a race condition and inconsistent responses).
As I have shown above your suggestion, introduces another race 
conditions - though its related to how callbacks are handled and not to 
disallowing concurrent asynchronous operations per se. Regarding race 
conditions I found another problem related to it: Lets consider a scenario
1 user browsed website A which asked him permission to find contacts, 
ignored permission dialog
2 user opened another tab and went to website B which uses Contacts.
In this case all calls on website B will fail because there is still 
pending security dialog on tab for page A.

> - User interaction is less confusing - only one permission request at 
> a time for the user to authorize.
>
As the browser can and probably will sequence the security dialogs the 
outcome will be the same sequence of X dialogs for X calls.
> ...FWIW, I do question the SysInfo API model: if a user is required to 
> authorize each SysInfo API call seperately it would probably make more 
> sense for a web app to be able to request a bunch of System 
> Information in a single API call (and hence a single permission 
> request). The current SysInfo API does not have the ability to provide 
> that yet :-(
>
I think that is not specific to SysInfo, but rather a generic problem of 
having very fine grained access control. Maybe we should have an API for 
establishing trust relation between user and the application. Something 
like
requestPermission(["deviceInfo.Power","deviceInfo.Network"...])
which would trigger a dialog asking for permission to multiple APIs 
where user can select which it allows, persistence etc..
>
> - Richard
>
>>     [1] http://www.w3.org/TR/IndexedDB/
>>     [2] http://dev.w3.org/html5/spec/Overview.html#file-upload-state
>>     [3] http://dev.w3.org/2009/dap/contacts/contacts_picker.png
>
>


-- 
Wojciech Masłowski
Engeneering CORE Wrocław
Opera Software ASA
http://www.opera.com
Received on Friday, 18 June 2010 15:07:19 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Wednesday, 9 May 2012 00:14:10 GMT