Marketplace/FirefoxAccounts/FxOS Control Flow

From MozillaWiki
Jump to: navigation, search
Stop (medium size).png
The Marketplace has been placed into maintenance mode. It is no longer under active development. You can read complete details here.
===================================================================

How calls to the Firefox Accounts navigator.mozId API are resolved on FirefoxOS

===================================================================

A work in progress; comments and corrections received gratefully. Terms


1. RP: "relying party", the application invoking the API Overview


The API has two methods: watch(), which must be called once and first, and request, which can be called whenever an assertion is wanted or, to trigger a password challenge, with the refreshAuthentication keyword. I. Initialization


1. The RP calls navigator.mozId.watch(options). options is a Javscript object containing one flag and five callbacks:

 {
   wantIssuer: "firefox-accounts",
   onReady: readyCB,
   onlogin: loginCB,
   onlogout: logoutCB,
   onerror: errorCB,
   onready: readyCB
 }

2. navigator.mozId is implemented in two files:

 - dom/identity/nsDOMIdentity.js (API exposed to web content)
 - dom/identity/DOMIdentity.jsm   (API exposed to the rest of Gecko)

When Firefox or FirefoxOS starts, it creates a single instance of DOMIdentity, the Gecko object (all of the Gecko objects in ".jsm" files are singletons). Each RP loads a separate instance of nsDOMIdentity. 3. nsDOMIdentity:watch() adds tracking information to the options blob, stores it, and sends it over the wall (via a "Child Process Message Manager") to DOMIdentity. 4. DOMIdentity stores the options blob, and passes it along to:

 - toolkit/identity/FirefoxAccounts.jsm:
     watch()

5. FirefoxAccounts also stores the blob before calling a method that does actual work:

 - services/fxaccounts/FxAccountsManager.jsm:
     getAssertion(blob.audience, {silent: true}).then()

6. FxAccountsManager manages state for FirefoxOS (aka "b2g") around the cross-platform:

 - services/fxaccounts/FxAccounts.jsm

getAssertion() checks for simple errors (such as no network or an unverified account). If it does not find them, it branches:

 - if the user is logged in, return an assertion to FirefoxAccounts.watch()
 - otherwise, the {silent: true} flag causes getAssertion() to return null

7. FirefoxAccounts passes what it receives, an assertion or null, back to DOMIdentity and then to nsDOMIdentity, via methods and messages labelled "doLogin" or "doLogout", respectively. 8. nsDOMIdentity fires either loginCB() or logoutCB() accordingly. If the RP supplied readyCB(), it calls that. II. Login


1. The RP calls navigator.mozId.request(), possibly passing in {oncancel: cancelCB}. 2. nsDOMIdentity.js sends a Request nsIMessage to DOMIdentity. 3. DOMIdentity passes it to FirefoxAccounts.request(). 4. FirefoxAccounts calls FxAccountsManager.getAssertion(). 5. getAssertion notices that there is no logged in user and calls _uiRequest(). 6. FxAccountsManager._uiRequest() creates a new instance of:

 b2g/components/FxAccountsUIGlue.js

and calls FxAccountsUIGlue.signInFlow(), which calls:

 SystemAppProxy._sendCustomEvent(
   "mozFxAccountsUnsolChromeEvent", 
   {eventName: "openFlow",
    id: <new uuid>,
    data: {}}
 );

and immediately returns a promise that will be fired by an event handler that listens for a

 "mozFxAccountsRPContentEvent"

7. Now we are in Gaia.

 - apps/system/js/fxa_manager.js
   handleEvent()

listens for the

 "mozFxAccountsUnsolChromeEvent"

from 6. (The same object uses "port" messages to talk to other Gaia components; see below.) 8. handleEvent branches on "openFlow" to:

 - apps/system/js/fxa_ui.js:FxAccountsUI
   login()

login() calls loadFlow(), which creates an iframe containing:

 - apps/system/fxa/fxa_module.html

and runs it via:

 - apps/system/js/fxa_dialog.js:FxAccountsDialog
   show()

9. Now the user works with the interactive login flow, as embodied by:

 - apps/system/fxa/js/fxam_*js
   (note the extra "fxa" directory in the path)

let's treat this as a black box; on closing it sends events to either done() or error() back in:

 - apps/system/js/fxa_ui.js:FxAccountsUI

10. done() and error() call onsuccessCB() and onerrorCB(), respectively, as passed to login() by fxa_manager.js:handleEvent(). Those two callbacks send

 'mozFxAccountsRPContentEvent'

which are listened for by onContentEvent(), the event handler created back in step 6. We are back in FxAccountsUIGlue.js 11. onContentEvent() resolves or rejects the promise that had been returned to FxAccountsManager._uiRequest(). 12. On a resolve(), _uiRequest() returns the value of:

 - services/fxaccounts/FxAccounts.jsm
   getAssertion()

which FxAccounts.getAssertion marshalls the data and performs the necessary crypto. A reject cascades via another reject in FxAccountsManager._error(). 13. Either way we return back through FxAccountsManager.getAssertion() to:

 - toolkit/identity/FirefoxAccounts.jsm
   request()

which called it in step 4. It passes the assertion or error back to DOMIdentity and then to nsDOMIdentity, via methods and messages labelled "doLogin" or "doError", very much as its watch() method finishes in I.7. 14. nsDOMIdentity.js receives the message from DOMIdentity and fires the onlogin() or onerror() callback that the RP passed to watch() back in I.1, or the oncancel() callback passed to request() in II.1