Bug 1262272 - Unconditionally poll the verification status for FxA push messages. r=markh
authorKit Cambridge <kcambridge@mozilla.com>
Mon, 11 Apr 2016 11:08:58 -0700
changeset 331065 536ea47e2684e30e28bbf927b7c5d6fb001ee637
parent 331064 7d08ffc48bac5c2f9a8c97f9d2b7d9677651e0af
child 331066 d0b6d063cf4981b3c893f511e84f6aac3a96b2f9
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh
bugs1262272
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1262272 - Unconditionally poll the verification status for FxA push messages. r=markh MozReview-Commit-ID: Fb7F1bxHO8V
services/fxaccounts/FxAccounts.jsm
services/fxaccounts/tests/xpcshell/test_accounts.js
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -416,17 +416,18 @@ FxAccountsInternal.prototype = {
   /**
    * Ask the server whether the user's email has been verified
    */
   checkEmailStatus: function checkEmailStatus(sessionToken, options = {}) {
     if (!sessionToken) {
       return Promise.reject(new Error(
         "checkEmailStatus called without a session token"));
     }
-    return this.fxAccountsClient.recoveryEmailStatus(sessionToken, options);
+    return this.fxAccountsClient.recoveryEmailStatus(sessionToken,
+      options).catch(error => this._handleTokenError(error));
   },
 
   /**
    * Once the user's email is verified, we can request the keys
    */
   fetchKeys: function fetchKeys(keyFetchToken) {
     log.debug("fetchKeys: " + !!keyFetchToken);
     if (logPII) {
@@ -668,20 +669,21 @@ FxAccountsInternal.prototype = {
     log.trace('checkVerificationStatus');
     let currentState = this.currentAccountState;
     return currentState.getUserAccountData().then(data => {
       if (!data) {
         log.trace("checkVerificationStatus - no user data");
         return null;
       }
 
-      if (!this.isUserEmailVerified(data)) {
-        log.trace("checkVerificationStatus - forcing verification status check");
-        this.pollEmailStatus(currentState, data.sessionToken, "push");
-      }
+      // Always check the verification status, even if the local state indicates
+      // we're already verified. If the user changed their password, the check
+      // will fail, and we'll enter the reauth state.
+      log.trace("checkVerificationStatus - forcing verification status check");
+      return this.pollEmailStatus(currentState, data.sessionToken, "push");
     });
   },
 
   _destroyOAuthToken: function(tokenData) {
     let client = new FxAccountsOAuthGrantClient({
       serverURL: tokenData.server,
       client_id: FX_OAUTH_CLIENT_ID
     });
@@ -1094,17 +1096,19 @@ FxAccountsInternal.prototype = {
         // handle a rejection" messages, so add an error handler directly
         // on the promise to log the error.
         currentState.whenVerifiedDeferred.promise.then(null, err => {
           log.info("the wait for user verification was stopped: " + err);
         });
       }
     }
 
-    this.checkEmailStatus(sessionToken, { reason: why })
+    // We return a promise for testing only. Other callers can ignore this,
+    // since verification polling continues in the background.
+    return this.checkEmailStatus(sessionToken, { reason: why })
       .then((response) => {
         log.debug("checkEmailStatus -> " + JSON.stringify(response));
         if (response && response.verified) {
           currentState.updateUserAccountData({ verified: true })
             .then(() => {
               return currentState.getUserAccountData();
             })
             .then(data => {
--- a/services/fxaccounts/tests/xpcshell/test_accounts.js
+++ b/services/fxaccounts/tests/xpcshell/test_accounts.js
@@ -1433,16 +1433,43 @@ add_test(function test_getSignedInUserPr
   fxa.getSignedInUserProfile()
     .catch(error => {
        do_check_eq(error.message, "NO_ACCOUNT");
        fxa.signOut().then(run_next_test);
     });
 
 });
 
+add_task(function* test_checkVerificationStatusFailed() {
+  let fxa = new MockFxAccounts();
+  let alice = getTestUser("alice");
+  alice.verified = true;
+
+  let client = fxa.internal.fxAccountsClient;
+  client.recoveryEmailStatus = () => {
+    return Promise.reject({
+      code: 401,
+      errno: ERRNO_INVALID_AUTH_TOKEN,
+    });
+  };
+  client.accountStatus = () => Promise.resolve(true);
+
+  yield fxa.setSignedInUser(alice);
+  let user = yield fxa.internal.getUserAccountData();
+  do_check_neq(alice.sessionToken, null);
+  do_check_eq(user.email, alice.email);
+  do_check_eq(user.verified, true);
+
+  yield fxa.checkVerificationStatus();
+
+  user = yield fxa.internal.getUserAccountData();
+  do_check_eq(user.email, alice.email);
+  do_check_eq(user.sessionToken, null);
+});
+
 /*
  * End of tests.
  * Utility functions follow.
  */
 
 function expandHex(two_hex) {
   // Return a 64-character hex string, encoding 32 identical bytes.
   let eight_hex = two_hex + two_hex + two_hex + two_hex;