diff --git a/services/sync/modules-testing/utils.js b/services/sync/modules-testing/utils.js index be6595783f7..c659263cf6f 100644 --- a/services/sync/modules-testing/utils.js +++ b/services/sync/modules-testing/utils.js @@ -31,6 +31,7 @@ Cu.import("resource://services-sync/browserid_identity.js"); Cu.import("resource://testing-common/services/common/logging.js"); Cu.import("resource://testing-common/services/sync/fakeservices.js"); Cu.import("resource://gre/modules/FxAccounts.jsm"); +Cu.import("resource://gre/modules/FxAccountsClient.jsm"); Cu.import("resource://gre/modules/FxAccountsCommon.js"); Cu.import("resource://gre/modules/Promise.jsm"); @@ -191,6 +192,18 @@ this.configureFxAccountIdentity = function(authService, }; fxa = new FxAccounts(MockInternal); + let MockFxAccountsClient = function() { + FxAccountsClient.apply(this); + }; + MockFxAccountsClient.prototype = { + __proto__: FxAccountsClient.prototype, + accountStatus() { + return Promise.resolve(true); + } + }; + let mockFxAClient = new MockFxAccountsClient(); + fxa.internal._fxAccountsClient = mockFxAClient; + let mockTSC = { // TokenServerClient getTokenFromBrowserIDAssertion: function(uri, assertion, cb) { config.fxaccount.token.uid = config.username; diff --git a/services/sync/modules/browserid_identity.js b/services/sync/modules/browserid_identity.js index 3d2c8f36e99..921540ce639 100644 --- a/services/sync/modules/browserid_identity.js +++ b/services/sync/modules/browserid_identity.js @@ -184,7 +184,7 @@ this.BrowserIDManager.prototype = { // Reset the world before we do anything async. this.whenReadyToAuthenticate = Promise.defer(); - this.whenReadyToAuthenticate.promise.then(null, (err) => { + this.whenReadyToAuthenticate.promise.catch(err => { this._log.error("Could not authenticate", err); }); @@ -240,14 +240,25 @@ this.BrowserIDManager.prototype = { Services.obs.notifyObservers(null, "weave:service:setup-complete", null); Weave.Utils.nextTick(Weave.Service.sync, Weave.Service); } - }).then(null, err => { - this._shouldHaveSyncKeyBundle = true; // but we probably don't have one... - this.whenReadyToAuthenticate.reject(err); + }).catch(err => { + let authErr = err; // note that we must reject with this error and not a + // subsequent one // report what failed... - this._log.error("Background fetch for key bundle failed", err); + this._log.error("Background fetch for key bundle failed", authErr); + // check if the account still exists + this._fxaService.accountStatus().then(exists => { + if (!exists) { + return fxAccounts.signOut(true); + } + }).catch(err => { + this._log.error("Error while trying to determine FXA existence", err); + }).then(() => { + this._shouldHaveSyncKeyBundle = true; // but we probably don't have one... + this.whenReadyToAuthenticate.reject(authErr) + }); }); // and we are done - the fetch continues on in the background... - }).then(null, err => { + }).catch(err => { this._log.error("Processing logged in account", err); }); }, @@ -595,7 +606,7 @@ this.BrowserIDManager.prototype = { } return token; }) - .then(null, err => { + .catch(err => { // TODO: unify these errors - we need to handle errors thrown by // both tokenserverclient and hawkclient. // A tokenserver error thrown based on a bad response. diff --git a/services/sync/tests/unit/test_browserid_identity.js b/services/sync/tests/unit/test_browserid_identity.js index b7bc965c550..82926417813 100644 --- a/services/sync/tests/unit/test_browserid_identity.js +++ b/services/sync/tests/unit/test_browserid_identity.js @@ -35,7 +35,10 @@ let MockFxAccountsClient = function() { FxAccountsClient.apply(this); }; MockFxAccountsClient.prototype = { - __proto__: FxAccountsClient.prototype + __proto__: FxAccountsClient.prototype, + accountStatus() { + return Promise.resolve(true); + } }; function MockFxAccounts() { @@ -83,6 +86,47 @@ add_task(function test_initialializeWithCurrentIdentity() { } ); +add_task(function test_initialializeWithAuthErrorAndDeletedAccount() { + _("Verify sync unpair after initializeWithCurrentIdentity with auth error + account deleted"); + + browseridManager._fxaService.internal.initialize(); + + let fetchTokenForUserCalled = false; + let accountStatusCalled = false; + + let MockFxAccountsClient = function() { + FxAccountsClient.apply(this); + }; + MockFxAccountsClient.prototype = { + __proto__: FxAccountsClient.prototype, + accountStatus() { + accountStatusCalled = true; + return Promise.resolve(false); + } + }; + + let mockFxAClient = new MockFxAccountsClient(); + browseridManager._fxaService.internal._fxAccountsClient = mockFxAClient; + + let oldFetchTokenForUser = browseridManager._fetchTokenForUser; + browseridManager._fetchTokenForUser = function() { + fetchTokenForUserCalled = true; + return Promise.reject(false); + } + + yield browseridManager.initializeWithCurrentIdentity(); + yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, + "should reject due to an auth error"); + + do_check_true(fetchTokenForUserCalled); + do_check_true(accountStatusCalled); + do_check_false(browseridManager.account); + do_check_false(browseridManager._token); + do_check_false(browseridManager.hasValidToken()); + do_check_false(browseridManager.account); + browseridManager._fetchTokenForUser = oldFetchTokenForUser; +}); + add_task(function test_initialializeWithNoKeys() { _("Verify start after initializeWithCurrentIdentity without kA, kB or keyFetchToken"); let identityConfig = makeIdentityConfig(); @@ -646,7 +690,17 @@ function* initializeIdentityWithHAWKResponseFactory(config, cbGetResponse) { callback.call(this); }, get: function(callback) { - this.response = cbGetResponse("get", null, this._uri, this._credentials, this._extra); + // Skip /status requests (browserid_identity checks if the account still + // exists after an auth error) + if (this._uri.startsWith("http://mockedserver:9999/account/status")) { + this.response = { + status: 200, + headers: {"content-type": "application/json"}, + body: JSON.stringify({exists: true}), + }; + } else { + this.response = cbGetResponse("get", null, this._uri, this._credentials, this._extra); + } callback.call(this); } } diff --git a/services/sync/tests/unit/test_fxa_migration.js b/services/sync/tests/unit/test_fxa_migration.js index 2feeff12690..ccb78d43c8a 100644 --- a/services/sync/tests/unit/test_fxa_migration.js +++ b/services/sync/tests/unit/test_fxa_migration.js @@ -1,3 +1,6 @@ +// We change this pref before anything else initializes +Services.prefs.setCharPref("identity.fxaccounts.auth.uri", "http://localhost"); + // Test the FxAMigration module Cu.import("resource://services-sync/FxaMigrator.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); @@ -80,12 +83,7 @@ function configureLegacySync() { return [engine, server]; } -function configureFxa() { - Services.prefs.setCharPref("identity.fxaccounts.auth.uri", "http://localhost"); -} - add_task(function *testMigration() { - configureFxa(); // when we do a .startOver we want the new provider. let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity");