Bug 982591 - Update TPS to retrieve keys from server instead of hard-coding them. r=warner, a=lsblakk
authorHenrik Skupin <mail@hskupin.info>
Fri, 21 Mar 2014 10:23:15 +0100
changeset 185055 2bf56d62dadc0179f882d56c92f75465f409d666
parent 185054 fa072a5c34decc2f4de0854b95d1388756a36200
child 185056 f7543e0fd69ed84129ea44cfbb4ff84183c229b7
push id5486
push userryanvm@gmail.com
push dateMon, 24 Mar 2014 17:56:16 +0000
treeherdermozilla-aurora@f7543e0fd69e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswarner, lsblakk
bugs982591
milestone30.0a2
Bug 982591 - Update TPS to retrieve keys from server instead of hard-coding them. r=warner, a=lsblakk
services/fxaccounts/FxAccounts.jsm
services/fxaccounts/FxAccountsClient.jsm
services/fxaccounts/tests/xpcshell/test_client.js
services/sync/tps/extensions/tps/resource/fxaccounts.jsm
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -355,23 +355,25 @@ FxAccountsInternal.prototype = {
 
   /**
    * Set the current user signed in to Firefox Accounts.
    *
    * @param credentials
    *        The credentials object obtained by logging in or creating
    *        an account on the FxA server:
    *        {
-   *          email: The users email address
-   *          uid: The user's unique id
-   *          sessionToken: Session for the FxA server
-   *          keyFetchToken: an unused keyFetchToken
-   *          verified: true/false
    *          authAt: The time (seconds since epoch) that this record was
    *                  authenticated
+   *          email: The users email address
+   *          keyFetchToken: a keyFetchToken which has not yet been used
+   *          sessionToken: Session for the FxA server
+   *          uid: The user's unique id
+   *          unwrapBKey: used to unwrap kB, derived locally from the
+   *                      password (not revealed to the FxA server)
+   *          verified: true/false
    *        }
    * @return Promise
    *         The promise resolves to null when the data is saved
    *         successfully and is rejected on error.
    */
   setSignedInUser: function setSignedInUser(credentials) {
     log.debug("setSignedInUser - aborting any existing flows");
     this.abortExistingFlow();
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -89,37 +89,41 @@ this.FxAccountsClient.prototype = {
    * @param [getKeys=false]
    *        If set to true the keyFetchToken will be retrieved
    * @param [retryOK=true]
    *        If capitalization of the email is wrong and retryOK is set to true,
    *        we will retry with the suggested capitalization from the server
    * @return Promise
    *        Returns a promise that resolves to an object:
    *        {
-   *          uid: the user's unique ID (hex)
-   *          sessionToken: a session token (hex)
-   *          keyFetchToken: a key fetch token (hex)
-   *          verified: flag indicating verification status of the email
    *          authAt: authentication time for the session (seconds since epoch)
    *          email: the primary email for this account
+   *          keyFetchToken: a key fetch token (hex)
+   *          sessionToken: a session token (hex)
+   *          uid: the user's unique ID (hex)
+   *          unwrapBKey: used to unwrap kB, derived locally from the
+   *                      password (not revealed to the FxA server)
+   *          verified: flag indicating verification status of the email
    *        }
    */
   signIn: function signIn(email, password, getKeys=false, retryOK=true) {
     return Credentials.setup(email, password).then((creds) => {
       let data = {
+        authPW: CommonUtils.bytesAsHex(creds.authPW),
         email: creds.emailUTF8,
-        authPW: CommonUtils.bytesAsHex(creds.authPW),
       };
       let keys = getKeys ? "?keys=true" : "";
 
       return this._request("/account/login" + keys, "POST", null, data).then(
         // Include the canonical capitalization of the email in the response so
         // the caller can set its signed-in user state accordingly.
         result => {
           result.email = data.email;
+          result.unwrapBKey = CommonUtils.bytesAsHex(creds.unwrapBKey);
+
           return result;
         },
         error => {
           log.debug("signIn error: " + JSON.stringify(error));
           // If the user entered an email with different capitalization from
           // what's stored in the database (e.g., Greta.Garbo@gmail.COM as
           // opposed to greta.garbo@gmail.com), the server will respond with a
           // errno 120 (code 400) and the expected capitalization of the email.
--- a/services/fxaccounts/tests/xpcshell/test_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_client.js
@@ -278,26 +278,32 @@ add_task(function test_signIn() {
       }
     },
   });
 
   // Login without retrieving optional keys
   let client = new FxAccountsClient(server.baseURI);
   let result = yield client.signIn('mé@example.com', 'bigsecret');
   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq(result.unwrapBKey,
+              "c076ec3f4af123a615157154c6e1d0d6293e514fd7b0221e32d50517ecf002b8");
   do_check_eq(undefined, result.keyFetchToken);
 
   // Login with retrieving optional keys
   let result = yield client.signIn('you@example.com', 'bigsecret', true);
   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq(result.unwrapBKey,
+              "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624");
   do_check_eq("keyFetchToken", result.keyFetchToken);
 
   // Retry due to wrong email capitalization
   let result = yield client.signIn('You@example.com', 'bigsecret', true);
   do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken);
+  do_check_eq(result.unwrapBKey,
+              "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624");
   do_check_eq("keyFetchToken", result.keyFetchToken);
 
   // Don't retry due to wrong email capitalization
   try {
     let result = yield client.signIn('You@example.com', 'bigsecret', true, false);
     do_throw("Expected to catch an exception");
   } catch (expectedError) {
     do_check_eq(120, expectedError.errno);
--- a/services/sync/tps/extensions/tps/resource/fxaccounts.jsm
+++ b/services/sync/tps/extensions/tps/resource/fxaccounts.jsm
@@ -5,16 +5,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = [
   "FxAccountsHelper",
 ];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
+Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
 Cu.import("resource://services-common/async.js");
 Cu.import("resource://services-sync/main.js");
 Cu.import("resource://tps/logger.jsm");
 
 
 /**
  * Helper object for Firefox Accounts authentication
@@ -28,27 +29,21 @@ var FxAccountsHelper = {
    *        The email address for the account (utf8)
    * @param password
    *        The user's password
    */
   signIn: function signIn(email, password) {
     let cb = Async.makeSpinningCallback();
 
     var client = new FxAccountsClient();
-    client.signIn(email, password).then(credentials => {
-      // Add keys because without those setSignedInUser() will fail
-      credentials.kA = 'foo';
-      credentials.kB = 'bar';
-
-      Weave.Service.identity._fxaService.setSignedInUser(credentials).then(() => {
-        cb(null);
-      }, err => {
-        cb(err);
-      });
-    }, (err) => {
+    client.signIn(email, password, true).then(credentials => {
+      return fxAccounts.setSignedInUser(credentials);
+    }).then(() => {
+      cb(null);
+    }, err => {
       cb(err);
     });
 
     try {
       cb.wait();
     } catch (err) {
       Logger.logError("signIn() failed with: " + JSON.stringify(err));
       throw err;