diff options
-rw-r--r-- | services/sync/modules-testing/fxa_utils.js | 58 | ||||
-rw-r--r-- | services/sync/modules-testing/utils.js | 85 | ||||
-rw-r--r-- | services/sync/moz.build | 1 | ||||
-rw-r--r-- | services/sync/tests/unit/test_browserid_identity.js | 682 | ||||
-rw-r--r-- | services/sync/tests/unit/test_load_modules.js | 1 | ||||
-rw-r--r-- | services/sync/tests/unit/xpcshell.ini | 1 | ||||
-rw-r--r-- | services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm | 96 | ||||
-rw-r--r-- | toolkit/components/passwordmgr/LoginHelper.jsm | 6 | ||||
-rw-r--r-- | toolkit/components/passwordmgr/storage-mozStorage.js | 2 | ||||
-rw-r--r-- | toolkit/identity/FirefoxAccounts.jsm | 313 | ||||
-rw-r--r-- | toolkit/identity/moz.build | 4 | ||||
-rw-r--r-- | toolkit/identity/tests/unit/test_firefox_accounts.js | 270 | ||||
-rw-r--r-- | toolkit/identity/tests/unit/xpcshell.ini | 1 | ||||
-rw-r--r-- | tools/lint/eslint/modules.json | 9 |
14 files changed, 7 insertions, 1522 deletions
diff --git a/services/sync/modules-testing/fxa_utils.js b/services/sync/modules-testing/fxa_utils.js deleted file mode 100644 index 70aa17b03e..0000000000 --- a/services/sync/modules-testing/fxa_utils.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict";
-
-this.EXPORTED_SYMBOLS = [
- "initializeIdentityWithTokenServerResponse",
-];
-
-var {utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://services-sync/main.js");
-Cu.import("resource://services-sync/browserid_identity.js");
-Cu.import("resource://services-common/tokenserverclient.js");
-Cu.import("resource://testing-common/services/common/logging.js");
-Cu.import("resource://testing-common/services/sync/utils.js");
-
-// Create a new browserid_identity object and initialize it with a
-// mocked TokenServerClient which always receives the specified response.
-this.initializeIdentityWithTokenServerResponse = function(response) {
- // First create a mock "request" object that well' hack into the token server.
- // A log for it
- let requestLog = Log.repository.getLogger("testing.mock-rest");
- if (!requestLog.appenders.length) { // might as well see what it says :)
- requestLog.addAppender(new Log.DumpAppender());
- requestLog.level = Log.Level.Trace;
- }
-
- // A mock request object.
- function MockRESTRequest(url) {};
- MockRESTRequest.prototype = {
- _log: requestLog,
- setHeader: function() {},
- get: function(callback) {
- this.response = response;
- callback.call(this);
- }
- }
- // The mocked TokenServer client which will get the response.
- function MockTSC() { }
- MockTSC.prototype = new TokenServerClient();
- MockTSC.prototype.constructor = MockTSC;
- MockTSC.prototype.newRESTRequest = function(url) {
- return new MockRESTRequest(url);
- }
- // Arrange for the same observerPrefix as browserid_identity uses.
- MockTSC.prototype.observerPrefix = "weave:service";
-
- // tie it all together.
- Weave.Status.__authManager = Weave.Service.identity = new BrowserIDManager();
- Weave.Service._clusterManager = Weave.Service.identity.createClusterManager(Weave.Service);
- let browseridManager = Weave.Service.identity;
- // a sanity check
- if (!(browseridManager instanceof BrowserIDManager)) {
- throw new Error("sync isn't configured for browserid_identity");
- }
- let mockTSC = new MockTSC()
- configureFxAccountIdentity(browseridManager);
- browseridManager._tokenServerClient = mockTSC;
-}
diff --git a/services/sync/modules-testing/utils.js b/services/sync/modules-testing/utils.js index fc14f2fbd8..64c9b163d6 100644 --- a/services/sync/modules-testing/utils.js +++ b/services/sync/modules-testing/utils.js @@ -28,8 +28,6 @@ Cu.import("resource://services-sync/util.js"); 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/FxAccountsCommon.js"); Cu.import("resource://gre/modules/Promise.jsm"); /** @@ -77,27 +75,8 @@ this.setBasicCredentials = this.makeIdentityConfig = function(overrides) { // first setup the defaults. let result = { - // Username used in both fxaccount and sync identity configs. + // Username used in sync identity config. username: "foo", - // fxaccount specific credentials. - fxaccount: { - user: { - assertion: 'assertion', - email: 'email', - kA: 'kA', - kB: 'kB', - sessionToken: 'sessionToken', - uid: 'user_uid', - verified: true, - }, - token: { - endpoint: Svc.Prefs.get("tokenServerURI"), - duration: 300, - id: "id", - key: "key", - // uid will be set to the username. - } - }, sync: { // username will come from the top-level username password: "whatever", @@ -114,64 +93,15 @@ this.makeIdentityConfig = function(overrides) { // TODO: allow just some attributes to be specified result.sync = overrides.sync; } - if (overrides.fxaccount) { - // TODO: allow just some attributes to be specified - result.fxaccount = overrides.fxaccount; - } } return result; } -// Configure an instance of an FxAccount identity provider with the specified -// config (or the default config if not specified). -this.configureFxAccountIdentity = function(authService, - config = makeIdentityConfig()) { - let MockInternal = {}; - let fxa = new FxAccounts(MockInternal); - - // until we get better test infrastructure for bid_identity, we set the - // signedin user's "email" to the username, simply as many tests rely on this. - config.fxaccount.user.email = config.username; - fxa.internal.currentAccountState.signedInUser = { - version: DATA_FORMAT_VERSION, - accountData: config.fxaccount.user - }; - fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) { - this.cert = { - validUntil: fxa.internal.now() + CERT_LIFETIME, - cert: "certificate", - }; - return Promise.resolve(this.cert.cert); - }; - - let mockTSC = { // TokenServerClient - getTokenFromBrowserIDAssertion: function(uri, assertion, cb) { - config.fxaccount.token.uid = config.username; - cb(null, config.fxaccount.token); - }, - }; - authService._fxaService = fxa; - authService._tokenServerClient = mockTSC; - // Set the "account" of the browserId manager to be the "email" of the - // logged in user of the mockFXA service. - authService._signedInUser = fxa.internal.currentAccountState.signedInUser.accountData; - authService._account = config.fxaccount.user.email; -} - this.configureIdentity = function(identityOverrides) { let config = makeIdentityConfig(identityOverrides); let ns = {}; Cu.import("resource://services-sync/service.js", ns); - if (ns.Service.identity instanceof BrowserIDManager) { - // do the FxAccounts thang... - configureFxAccountIdentity(ns.Service.identity, config); - return ns.Service.identity.initializeWithCurrentIdentity().then(() => { - // need to wait until this identity manager is readyToAuthenticate. - return ns.Service.identity.whenReadyToAuthenticate.promise; - }); - } - // old style identity provider. setBasicCredentials(config.username, config.sync.password, config.sync.syncKey); let deferred = Promise.defer(); deferred.resolve(); @@ -184,7 +114,6 @@ this.SyncTestingInfrastructure = function (server, username, password, syncKey) ensureLegacyIdentityManager(); let config = makeIdentityConfig(); - // XXX - hacks for the sync identity provider. if (username) config.username = username; if (password) @@ -223,10 +152,10 @@ this.encryptPayload = function encryptPayload(cleartext) { }; } -// This helper can be used instead of 'add_test' or 'add_task' to run the +// This helper was used instead of 'add_test' or 'add_task' to run the // specified test function twice - once with the old-style sync identity // manager and once with the new-style BrowserID identity manager, to ensure -// it works in both cases. +// it worked in both cases. Currently it's equal to just one. XXX: cleanup? // // * The test itself should be passed as 'test' - ie, test code will generally // pass |this|. @@ -248,12 +177,4 @@ this.add_identity_test = function(test, testFunction) { yield testFunction(); Status.__authManager = ns.Service.identity = oldIdentity; }); - // another task for the FxAccounts identity manager. - test.add_task(function() { - note("FxAccounts"); - let oldIdentity = Status._authManager; - Status.__authManager = ns.Service.identity = new BrowserIDManager(); - yield testFunction(); - Status.__authManager = ns.Service.identity = oldIdentity; - }); } diff --git a/services/sync/moz.build b/services/sync/moz.build index ceb4eb5022..56421a03ee 100644 --- a/services/sync/moz.build +++ b/services/sync/moz.build @@ -54,7 +54,6 @@ EXTRA_JS_MODULES['services-sync'].stages += [ TESTING_JS_MODULES.services.sync += [ 'modules-testing/fakeservices.js', - 'modules-testing/fxa_utils.js', 'modules-testing/rotaryengine.js', 'modules-testing/utils.js', ] diff --git a/services/sync/tests/unit/test_browserid_identity.js b/services/sync/tests/unit/test_browserid_identity.js deleted file mode 100644 index f3cde9f8f9..0000000000 --- a/services/sync/tests/unit/test_browserid_identity.js +++ /dev/null @@ -1,682 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -Cu.import("resource://gre/modules/FxAccounts.jsm"); -Cu.import("resource://services-sync/browserid_identity.js"); -Cu.import("resource://services-sync/rest.js"); -Cu.import("resource://services-sync/util.js"); -Cu.import("resource://services-common/utils.js"); -Cu.import("resource://services-crypto/utils.js"); -Cu.import("resource://testing-common/services/sync/utils.js"); -Cu.import("resource://testing-common/services/sync/fxa_utils.js"); -Cu.import("resource://services-common/hawkclient.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://services-sync/service.js"); -Cu.import("resource://services-sync/status.js"); -Cu.import("resource://services-sync/constants.js"); - -const SECOND_MS = 1000; -const MINUTE_MS = SECOND_MS * 60; -const HOUR_MS = MINUTE_MS * 60; - -let identityConfig = makeIdentityConfig(); -let browseridManager = new BrowserIDManager(); -configureFxAccountIdentity(browseridManager, identityConfig); - -/** - * Mock client clock and skew vs server in FxAccounts signed-in user module and - * API client. browserid_identity.js queries these values to construct HAWK - * headers. We will use this to test clock skew compensation in these headers - * below. - */ -let MockFxAccountsClient = function() { - FxAccountsClient.apply(this); -}; -MockFxAccountsClient.prototype = { - __proto__: FxAccountsClient.prototype -}; - -function MockFxAccounts() { - let fxa = new FxAccounts({ - _now_is: Date.now(), - - now: function () { - return this._now_is; - }, - - fxAccountsClient: new MockFxAccountsClient() - }); - fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) { - this.cert = { - validUntil: fxa.internal.now() + CERT_LIFETIME, - cert: "certificate", - }; - return Promise.resolve(this.cert.cert); - }; - return fxa; -} - -function run_test() { - initTestLogging("Trace"); - Log.repository.getLogger("Sync.Identity").level = Log.Level.Trace; - Log.repository.getLogger("Sync.BrowserIDManager").level = Log.Level.Trace; - run_next_test(); -}; - -add_test(function test_initial_state() { - _("Verify initial state"); - do_check_false(!!browseridManager._token); - do_check_false(browseridManager.hasValidToken()); - run_next_test(); - } -); - -add_task(function test_initialializeWithCurrentIdentity() { - _("Verify start after initializeWithCurrentIdentity"); - browseridManager.initializeWithCurrentIdentity(); - yield browseridManager.whenReadyToAuthenticate.promise; - do_check_true(!!browseridManager._token); - do_check_true(browseridManager.hasValidToken()); - do_check_eq(browseridManager.account, identityConfig.fxaccount.user.email); - } -); - -add_task(function test_initialializeWithNoKeys() { - _("Verify start after initializeWithCurrentIdentity without kA, kB or keyFetchToken"); - let identityConfig = makeIdentityConfig(); - delete identityConfig.fxaccount.user.kA; - delete identityConfig.fxaccount.user.kB; - // there's no keyFetchToken by default, so the initialize should fail. - configureFxAccountIdentity(browseridManager, identityConfig); - - yield browseridManager.initializeWithCurrentIdentity(); - yield browseridManager.whenReadyToAuthenticate.promise; - do_check_eq(Status.login, LOGIN_SUCCEEDED, "login succeeded even without keys"); - do_check_false(browseridManager._canFetchKeys(), "_canFetchKeys reflects lack of keys"); - do_check_eq(browseridManager._token, null, "we don't have a token"); -}); - -add_test(function test_getResourceAuthenticator() { - _("BrowserIDManager supplies a Resource Authenticator callback which returns a Hawk header."); - configureFxAccountIdentity(browseridManager); - let authenticator = browseridManager.getResourceAuthenticator(); - do_check_true(!!authenticator); - let req = {uri: CommonUtils.makeURI( - "https://example.net/somewhere/over/the/rainbow"), - method: 'GET'}; - let output = authenticator(req, 'GET'); - do_check_true('headers' in output); - do_check_true('authorization' in output.headers); - do_check_true(output.headers.authorization.startsWith('Hawk')); - _("Expected internal state after successful call."); - do_check_eq(browseridManager._token.uid, identityConfig.fxaccount.token.uid); - run_next_test(); - } -); - -add_test(function test_getRESTRequestAuthenticator() { - _("BrowserIDManager supplies a REST Request Authenticator callback which sets a Hawk header on a request object."); - let request = new SyncStorageRequest( - "https://example.net/somewhere/over/the/rainbow"); - let authenticator = browseridManager.getRESTRequestAuthenticator(); - do_check_true(!!authenticator); - let output = authenticator(request, 'GET'); - do_check_eq(request.uri, output.uri); - do_check_true(output._headers.authorization.startsWith('Hawk')); - do_check_true(output._headers.authorization.includes('nonce')); - do_check_true(browseridManager.hasValidToken()); - run_next_test(); - } -); - -add_test(function test_resourceAuthenticatorSkew() { - _("BrowserIDManager Resource Authenticator compensates for clock skew in Hawk header."); - - // Clock is skewed 12 hours into the future - // We pick a date in the past so we don't risk concealing bugs in code that - // uses new Date() instead of our given date. - let now = new Date("Fri Apr 09 2004 00:00:00 GMT-0700").valueOf() + 12 * HOUR_MS; - let browseridManager = new BrowserIDManager(); - let hawkClient = new HawkClient("https://example.net/v1", "/foo"); - - // mock fxa hawk client skew - hawkClient.now = function() { - dump("mocked client now: " + now + '\n'); - return now; - } - // Imagine there's already been one fxa request and the hawk client has - // already detected skew vs the fxa auth server. - let localtimeOffsetMsec = -1 * 12 * HOUR_MS; - hawkClient._localtimeOffsetMsec = localtimeOffsetMsec; - - let fxaClient = new MockFxAccountsClient(); - fxaClient.hawk = hawkClient; - - // Sanity check - do_check_eq(hawkClient.now(), now); - do_check_eq(hawkClient.localtimeOffsetMsec, localtimeOffsetMsec); - - // Properly picked up by the client - do_check_eq(fxaClient.now(), now); - do_check_eq(fxaClient.localtimeOffsetMsec, localtimeOffsetMsec); - - let fxa = new MockFxAccounts(); - fxa.internal._now_is = now; - fxa.internal.fxAccountsClient = fxaClient; - - // Picked up by the signed-in user module - do_check_eq(fxa.internal.now(), now); - do_check_eq(fxa.internal.localtimeOffsetMsec, localtimeOffsetMsec); - - do_check_eq(fxa.now(), now); - do_check_eq(fxa.localtimeOffsetMsec, localtimeOffsetMsec); - - // Mocks within mocks... - configureFxAccountIdentity(browseridManager, identityConfig); - - // Ensure the new FxAccounts mock has a signed-in user. - fxa.internal.currentAccountState.signedInUser = browseridManager._fxaService.internal.currentAccountState.signedInUser; - - browseridManager._fxaService = fxa; - - do_check_eq(browseridManager._fxaService.internal.now(), now); - do_check_eq(browseridManager._fxaService.internal.localtimeOffsetMsec, - localtimeOffsetMsec); - - do_check_eq(browseridManager._fxaService.now(), now); - do_check_eq(browseridManager._fxaService.localtimeOffsetMsec, - localtimeOffsetMsec); - - let request = new SyncStorageRequest("https://example.net/i/like/pie/"); - let authenticator = browseridManager.getResourceAuthenticator(); - let output = authenticator(request, 'GET'); - dump("output" + JSON.stringify(output)); - let authHeader = output.headers.authorization; - do_check_true(authHeader.startsWith('Hawk')); - - // Skew correction is applied in the header and we're within the two-minute - // window. - do_check_eq(getTimestamp(authHeader), now - 12 * HOUR_MS); - do_check_true( - (getTimestampDelta(authHeader, now) - 12 * HOUR_MS) < 2 * MINUTE_MS); - - run_next_test(); -}); - -add_test(function test_RESTResourceAuthenticatorSkew() { - _("BrowserIDManager REST Resource Authenticator compensates for clock skew in Hawk header."); - - // Clock is skewed 12 hours into the future from our arbitary date - let now = new Date("Fri Apr 09 2004 00:00:00 GMT-0700").valueOf() + 12 * HOUR_MS; - let browseridManager = new BrowserIDManager(); - let hawkClient = new HawkClient("https://example.net/v1", "/foo"); - - // mock fxa hawk client skew - hawkClient.now = function() { - return now; - } - // Imagine there's already been one fxa request and the hawk client has - // already detected skew vs the fxa auth server. - hawkClient._localtimeOffsetMsec = -1 * 12 * HOUR_MS; - - let fxaClient = new MockFxAccountsClient(); - fxaClient.hawk = hawkClient; - let fxa = new MockFxAccounts(); - fxa.internal._now_is = now; - fxa.internal.fxAccountsClient = fxaClient; - - configureFxAccountIdentity(browseridManager, identityConfig); - - // Ensure the new FxAccounts mock has a signed-in user. - fxa.internal.currentAccountState.signedInUser = browseridManager._fxaService.internal.currentAccountState.signedInUser; - - browseridManager._fxaService = fxa; - - do_check_eq(browseridManager._fxaService.internal.now(), now); - - let request = new SyncStorageRequest("https://example.net/i/like/pie/"); - let authenticator = browseridManager.getResourceAuthenticator(); - let output = authenticator(request, 'GET'); - dump("output" + JSON.stringify(output)); - let authHeader = output.headers.authorization; - do_check_true(authHeader.startsWith('Hawk')); - - // Skew correction is applied in the header and we're within the two-minute - // window. - do_check_eq(getTimestamp(authHeader), now - 12 * HOUR_MS); - do_check_true( - (getTimestampDelta(authHeader, now) - 12 * HOUR_MS) < 2 * MINUTE_MS); - - run_next_test(); -}); - -add_task(function test_ensureLoggedIn() { - configureFxAccountIdentity(browseridManager); - yield browseridManager.initializeWithCurrentIdentity(); - yield browseridManager.whenReadyToAuthenticate.promise; - Assert.equal(Status.login, LOGIN_SUCCEEDED, "original initialize worked"); - yield browseridManager.ensureLoggedIn(); - Assert.equal(Status.login, LOGIN_SUCCEEDED, "original ensureLoggedIn worked"); - Assert.ok(browseridManager._shouldHaveSyncKeyBundle, - "_shouldHaveSyncKeyBundle should always be true after ensureLogin completes."); - - // arrange for no logged in user. - let fxa = browseridManager._fxaService - let signedInUser = fxa.internal.currentAccountState.signedInUser; - fxa.internal.currentAccountState.signedInUser = null; - browseridManager.initializeWithCurrentIdentity(); - Assert.ok(!browseridManager._shouldHaveSyncKeyBundle, - "_shouldHaveSyncKeyBundle should be false so we know we are testing what we think we are."); - Status.login = LOGIN_FAILED_NO_USERNAME; - yield Assert.rejects(browseridManager.ensureLoggedIn(), "expecting rejection due to no user"); - Assert.ok(browseridManager._shouldHaveSyncKeyBundle, - "_shouldHaveSyncKeyBundle should always be true after ensureLogin completes."); - fxa.internal.currentAccountState.signedInUser = signedInUser; - Status.login = LOGIN_FAILED_LOGIN_REJECTED; - yield Assert.rejects(browseridManager.ensureLoggedIn(), - "LOGIN_FAILED_LOGIN_REJECTED should have caused immediate rejection"); - Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, - "status should remain LOGIN_FAILED_LOGIN_REJECTED"); - Status.login = LOGIN_FAILED_NETWORK_ERROR; - yield browseridManager.ensureLoggedIn(); - Assert.equal(Status.login, LOGIN_SUCCEEDED, "final ensureLoggedIn worked"); -}); - -add_test(function test_tokenExpiration() { - _("BrowserIDManager notices token expiration:"); - let bimExp = new BrowserIDManager(); - configureFxAccountIdentity(bimExp, identityConfig); - - let authenticator = bimExp.getResourceAuthenticator(); - do_check_true(!!authenticator); - let req = {uri: CommonUtils.makeURI( - "https://example.net/somewhere/over/the/rainbow"), - method: 'GET'}; - authenticator(req, 'GET'); - - // Mock the clock. - _("Forcing the token to expire ..."); - Object.defineProperty(bimExp, "_now", { - value: function customNow() { - return (Date.now() + 3000001); - }, - writable: true, - }); - do_check_true(bimExp._token.expiration < bimExp._now()); - _("... means BrowserIDManager knows to re-fetch it on the next call."); - do_check_false(bimExp.hasValidToken()); - run_next_test(); - } -); - -add_test(function test_sha256() { - // Test vectors from http://www.bichlmeier.info/sha256test.html - let vectors = [ - ["", - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"], - ["abc", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"], - ["message digest", - "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"], - ["secure hash algorithm", - "f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d"], - ["SHA256 is considered to be safe", - "6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630"], - ["abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"], - ["For this sample, this 63-byte string will be used as input data", - "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342"], - ["This is exactly 64 bytes long, not counting the terminating byte", - "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8"] - ]; - let bidUser = new BrowserIDManager(); - for (let [input,output] of vectors) { - do_check_eq(CommonUtils.bytesAsHex(bidUser._sha256(input)), output); - } - run_next_test(); -}); - -add_test(function test_computeXClientStateHeader() { - let kBhex = "fd5c747806c07ce0b9d69dcfea144663e630b65ec4963596a22f24910d7dd15d"; - let kB = CommonUtils.hexToBytes(kBhex); - - let bidUser = new BrowserIDManager(); - let header = bidUser._computeXClientState(kB); - - do_check_eq(header, "6ae94683571c7a7c54dab4700aa3995f"); - run_next_test(); -}); - -add_task(function test_getTokenErrors() { - _("BrowserIDManager correctly handles various failures to get a token."); - - _("Arrange for a 401 - Sync should reflect an auth error."); - initializeIdentityWithTokenServerResponse({ - status: 401, - headers: {"content-type": "application/json"}, - body: JSON.stringify({}), - }); - let browseridManager = Service.identity; - - yield browseridManager.initializeWithCurrentIdentity(); - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to 401"); - Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected"); - - // XXX - other interesting responses to return? - - // And for good measure, some totally "unexpected" errors - we generally - // assume these problems are going to magically go away at some point. - _("Arrange for an empty body with a 200 response - should reflect a network error."); - initializeIdentityWithTokenServerResponse({ - status: 200, - headers: [], - body: "", - }); - browseridManager = Service.identity; - yield browseridManager.initializeWithCurrentIdentity(); - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to non-JSON response"); - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR"); -}); - -add_task(function test_getTokenErrorWithRetry() { - _("tokenserver sends an observer notification on various backoff headers."); - - // Set Sync's backoffInterval to zero - after we simulated the backoff header - // it should reflect the value we sent. - Status.backoffInterval = 0; - _("Arrange for a 503 with a Retry-After header."); - initializeIdentityWithTokenServerResponse({ - status: 503, - headers: {"content-type": "application/json", - "retry-after": "100"}, - body: JSON.stringify({}), - }); - let browseridManager = Service.identity; - - yield browseridManager.initializeWithCurrentIdentity(); - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to 503"); - - // The observer should have fired - check it got the value in the response. - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected"); - // Sync will have the value in ms with some slop - so check it is at least that. - Assert.ok(Status.backoffInterval >= 100000); - - _("Arrange for a 200 with an X-Backoff header."); - Status.backoffInterval = 0; - initializeIdentityWithTokenServerResponse({ - status: 503, - headers: {"content-type": "application/json", - "x-backoff": "200"}, - body: JSON.stringify({}), - }); - browseridManager = Service.identity; - - yield browseridManager.initializeWithCurrentIdentity(); - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to no token in response"); - - // The observer should have fired - check it got the value in the response. - Assert.ok(Status.backoffInterval >= 200000); -}); - -add_task(function test_getKeysErrorWithBackoff() { - _("Auth server (via hawk) sends an observer notification on backoff headers."); - - // Set Sync's backoffInterval to zero - after we simulated the backoff header - // it should reflect the value we sent. - Status.backoffInterval = 0; - _("Arrange for a 503 with a X-Backoff header."); - - let config = makeIdentityConfig(); - // We want no kA or kB so we attempt to fetch them. - delete config.fxaccount.user.kA; - delete config.fxaccount.user.kB; - config.fxaccount.user.keyFetchToken = "keyfetchtoken"; - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "get"); - Assert.equal(uri, "http://mockedserver:9999/account/keys") - return { - status: 503, - headers: {"content-type": "application/json", - "x-backoff": "100"}, - body: "{}", - } - }); - - let browseridManager = Service.identity; - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to 503"); - - // The observer should have fired - check it got the value in the response. - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected"); - // Sync will have the value in ms with some slop - so check it is at least that. - Assert.ok(Status.backoffInterval >= 100000); -}); - -add_task(function test_getKeysErrorWithRetry() { - _("Auth server (via hawk) sends an observer notification on retry headers."); - - // Set Sync's backoffInterval to zero - after we simulated the backoff header - // it should reflect the value we sent. - Status.backoffInterval = 0; - _("Arrange for a 503 with a Retry-After header."); - - let config = makeIdentityConfig(); - // We want no kA or kB so we attempt to fetch them. - delete config.fxaccount.user.kA; - delete config.fxaccount.user.kB; - config.fxaccount.user.keyFetchToken = "keyfetchtoken"; - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "get"); - Assert.equal(uri, "http://mockedserver:9999/account/keys") - return { - status: 503, - headers: {"content-type": "application/json", - "retry-after": "100"}, - body: "{}", - } - }); - - let browseridManager = Service.identity; - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "should reject due to 503"); - - // The observer should have fired - check it got the value in the response. - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login was rejected"); - // Sync will have the value in ms with some slop - so check it is at least that. - Assert.ok(Status.backoffInterval >= 100000); -}); - -add_task(function test_getHAWKErrors() { - _("BrowserIDManager correctly handles various HAWK failures."); - - _("Arrange for a 401 - Sync should reflect an auth error."); - let config = makeIdentityConfig(); - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "post"); - Assert.equal(uri, "http://mockedserver:9999/certificate/sign") - return { - status: 401, - headers: {"content-type": "application/json"}, - body: JSON.stringify({}), - } - }); - Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected"); - - // XXX - other interesting responses to return? - - // And for good measure, some totally "unexpected" errors - we generally - // assume these problems are going to magically go away at some point. - _("Arrange for an empty body with a 200 response - should reflect a network error."); - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "post"); - Assert.equal(uri, "http://mockedserver:9999/certificate/sign") - return { - status: 200, - headers: [], - body: "", - } - }); - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "login state is LOGIN_FAILED_NETWORK_ERROR"); -}); - -add_task(function test_getGetKeysFailing401() { - _("BrowserIDManager correctly handles 401 responses fetching keys."); - - _("Arrange for a 401 - Sync should reflect an auth error."); - let config = makeIdentityConfig(); - // We want no kA or kB so we attempt to fetch them. - delete config.fxaccount.user.kA; - delete config.fxaccount.user.kB; - config.fxaccount.user.keyFetchToken = "keyfetchtoken"; - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "get"); - Assert.equal(uri, "http://mockedserver:9999/account/keys") - return { - status: 401, - headers: {"content-type": "application/json"}, - body: "{}", - } - }); - Assert.equal(Status.login, LOGIN_FAILED_LOGIN_REJECTED, "login was rejected"); -}); - -add_task(function test_getGetKeysFailing503() { - _("BrowserIDManager correctly handles 5XX responses fetching keys."); - - _("Arrange for a 503 - Sync should reflect a network error."); - let config = makeIdentityConfig(); - // We want no kA or kB so we attempt to fetch them. - delete config.fxaccount.user.kA; - delete config.fxaccount.user.kB; - config.fxaccount.user.keyFetchToken = "keyfetchtoken"; - yield initializeIdentityWithHAWKResponseFactory(config, function(method, data, uri) { - Assert.equal(method, "get"); - Assert.equal(uri, "http://mockedserver:9999/account/keys") - return { - status: 503, - headers: {"content-type": "application/json"}, - body: "{}", - } - }); - Assert.equal(Status.login, LOGIN_FAILED_NETWORK_ERROR, "state reflects network error"); -}); - -add_task(function test_getKeysMissing() { - _("BrowserIDManager correctly handles getKeys succeeding but not returning keys."); - - let browseridManager = new BrowserIDManager(); - let identityConfig = makeIdentityConfig(); - // our mock identity config already has kA and kB - remove them or we never - // try and fetch them. - delete identityConfig.fxaccount.user.kA; - delete identityConfig.fxaccount.user.kB; - identityConfig.fxaccount.user.keyFetchToken = 'keyFetchToken'; - - configureFxAccountIdentity(browseridManager, identityConfig); - - // Mock a fxAccounts object that returns no keys - let fxa = new FxAccounts({ - fetchAndUnwrapKeys: function () { - return Promise.resolve({}); - }, - fxAccountsClient: new MockFxAccountsClient() - }); - - // Add a mock to the currentAccountState object. - fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) { - this.cert = { - validUntil: fxa.internal.now() + CERT_LIFETIME, - cert: "certificate", - }; - return Promise.resolve(this.cert.cert); - }; - - // Ensure the new FxAccounts mock has a signed-in user. - fxa.internal.currentAccountState.signedInUser = browseridManager._fxaService.internal.currentAccountState.signedInUser; - - browseridManager._fxaService = fxa; - - yield browseridManager.initializeWithCurrentIdentity(); - - let ex; - try { - yield browseridManager.whenReadyToAuthenticate.promise; - } catch (e) { - ex = e; - } - - Assert.ok(ex.message.indexOf("missing kA or kB") >= 0); -}); - -// End of tests -// Utility functions follow - -// Create a new browserid_identity object and initialize it with a -// hawk mock that simulates HTTP responses. -// The callback function will be called each time the mocked hawk server wants -// to make a request. The result of the callback should be the mock response -// object that will be returned to hawk. -// A token server mock will be used that doesn't hit a server, so we move -// directly to a hawk request. -function* initializeIdentityWithHAWKResponseFactory(config, cbGetResponse) { - // A mock request object. - function MockRESTRequest(uri, credentials, extra) { - this._uri = uri; - this._credentials = credentials; - this._extra = extra; - }; - MockRESTRequest.prototype = { - setHeader: function() {}, - post: function(data, callback) { - this.response = cbGetResponse("post", data, this._uri, this._credentials, this._extra); - callback.call(this); - }, - get: function(callback) { - this.response = cbGetResponse("get", null, this._uri, this._credentials, this._extra); - callback.call(this); - } - } - - // The hawk client. - function MockedHawkClient() {} - MockedHawkClient.prototype = new HawkClient("http://mockedserver:9999"); - MockedHawkClient.prototype.constructor = MockedHawkClient; - MockedHawkClient.prototype.newHAWKAuthenticatedRESTRequest = function(uri, credentials, extra) { - return new MockRESTRequest(uri, credentials, extra); - } - // Arrange for the same observerPrefix as FxAccountsClient uses - MockedHawkClient.prototype.observerPrefix = "FxA:hawk"; - - // tie it all together - configureFxAccountIdentity isn't useful here :( - let fxaClient = new MockFxAccountsClient(); - fxaClient.hawk = new MockedHawkClient(); - let internal = { - fxAccountsClient: fxaClient, - } - let fxa = new FxAccounts(internal); - fxa.internal.currentAccountState.signedInUser = { - accountData: config.fxaccount.user, - }; - - browseridManager._fxaService = fxa; - browseridManager._signedInUser = null; - yield browseridManager.initializeWithCurrentIdentity(); - yield Assert.rejects(browseridManager.whenReadyToAuthenticate.promise, - "expecting rejection due to hawk error"); -} - - -function getTimestamp(hawkAuthHeader) { - return parseInt(/ts="(\d+)"/.exec(hawkAuthHeader)[1], 10) * SECOND_MS; -} - -function getTimestampDelta(hawkAuthHeader, now=Date.now()) { - return Math.abs(getTimestamp(hawkAuthHeader) - now); -} - diff --git a/services/sync/tests/unit/test_load_modules.js b/services/sync/tests/unit/test_load_modules.js index 4f561bae62..8e3fcf1f3c 100644 --- a/services/sync/tests/unit/test_load_modules.js +++ b/services/sync/tests/unit/test_load_modules.js @@ -37,7 +37,6 @@ const testingModules = [ "fakeservices.js", "rotaryengine.js", "utils.js", - "fxa_utils.js", ]; function run_test() { diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini index 28424129bb..2f98847516 100644 --- a/services/sync/tests/unit/xpcshell.ini +++ b/services/sync/tests/unit/xpcshell.ini @@ -50,7 +50,6 @@ skip-if = os == "win" || os == "android" [test_syncstoragerequest.js] # Generic Sync types. -[test_browserid_identity.js] [test_collection_inc_get.js] [test_collections_recovery.js] [test_identity_manager.js] diff --git a/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm b/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm deleted file mode 100644 index f5daa14be7..0000000000 --- a/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm +++ /dev/null @@ -1,96 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = [ - "Authentication", -]; - -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 - */ -var Authentication = { - - /** - * Check if an user has been logged in - */ - get isLoggedIn() { - return !!this.getSignedInUser(); - }, - - /** - * Wrapper to retrieve the currently signed in user - * - * @returns Information about the currently signed in user - */ - getSignedInUser: function getSignedInUser() { - let cb = Async.makeSpinningCallback(); - - fxAccounts.getSignedInUser().then(user => { - cb(null, user); - }, error => { - cb(error); - }) - - try { - return cb.wait(); - } catch (error) { - Logger.logError("getSignedInUser() failed with: " + JSON.stringify(error)); - throw error; - } - }, - - /** - * Wrapper to synchronize the login of a user - * - * @param account - * Account information of the user to login - * @param account.username - * The username for the account (utf8) - * @param account.password - * The user's password - */ - signIn: function signIn(account) { - let cb = Async.makeSpinningCallback(); - - Logger.AssertTrue(account["username"], "Username has been found"); - Logger.AssertTrue(account["password"], "Password has been found"); - - Logger.logInfo("Login user: " + account["username"] + '\n'); - - let client = new FxAccountsClient(); - client.signIn(account["username"], account["password"], true).then(credentials => { - return fxAccounts.setSignedInUser(credentials); - }).then(() => { - cb(null, true); - }, error => { - cb(error, false); - }); - - try { - cb.wait(); - - if (Weave.Status.login !== Weave.LOGIN_SUCCEEDED) { - Logger.logInfo("Logging into Weave."); - Weave.Service.login(); - Logger.AssertEqual(Weave.Status.login, Weave.LOGIN_SUCCEEDED, - "Weave logged in"); - } - - return true; - } catch (error) { - throw new Error("signIn() failed with: " + error.message); - } - } -}; diff --git a/toolkit/components/passwordmgr/LoginHelper.jsm b/toolkit/components/passwordmgr/LoginHelper.jsm index e0c4d872b6..c6cd40915a 100644 --- a/toolkit/components/passwordmgr/LoginHelper.jsm +++ b/toolkit/components/passwordmgr/LoginHelper.jsm @@ -202,7 +202,7 @@ this.LoginHelper = { return true; } } catch (ex) { - // newURI will throw for some values e.g. chrome://FirefoxAccounts + // newURI will throw for some values return false; } } @@ -406,7 +406,7 @@ this.LoginHelper = { try { preferredOriginScheme = Services.io.newURI(preferredOrigin, null, null).scheme; } catch (ex) { - // Handle strings that aren't valid URIs e.g. chrome://FirefoxAccounts + // Handle strings that aren't valid URIs } } @@ -457,7 +457,7 @@ this.LoginHelper = { return loginURI.scheme == preferredOriginScheme; } catch (ex) { - // Some URLs aren't valid nsIURI (e.g. chrome://FirefoxAccounts) + // Some URLs aren't valid nsIURI log.debug("dedupeLogins/shouldReplaceExisting: Error comparing schemes:", existingLogin.hostname, login.hostname, "preferredOrigin:", preferredOrigin, ex); diff --git a/toolkit/components/passwordmgr/storage-mozStorage.js b/toolkit/components/passwordmgr/storage-mozStorage.js index 7fc9e57fd5..9da244f7a3 100644 --- a/toolkit/components/passwordmgr/storage-mozStorage.js +++ b/toolkit/components/passwordmgr/storage-mozStorage.js @@ -471,7 +471,7 @@ LoginManagerStorage_mozStorage.prototype = { params["http" + field] = "http://" + valueURI.hostPort; } } catch (ex) { - // newURI will throw for some values (e.g. chrome://FirefoxAccounts) + // newURI will throw for some values // but those URLs wouldn't support upgrades anyways. } break; diff --git a/toolkit/identity/FirefoxAccounts.jsm b/toolkit/identity/FirefoxAccounts.jsm deleted file mode 100644 index 1d2ed04397..0000000000 --- a/toolkit/identity/FirefoxAccounts.jsm +++ /dev/null @@ -1,313 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["FirefoxAccounts"]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Log.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/identity/LogUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "objectCopy", - "resource://gre/modules/identity/IdentityUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "makeMessageObject", - "resource://gre/modules/identity/IdentityUtils.jsm"); - -// loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO", -// "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by -// default. -const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel"; -try { - this.LOG_LEVEL = - Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING - && Services.prefs.getCharPref(PREF_LOG_LEVEL); -} catch (e) { - this.LOG_LEVEL = Log.Level.Error; -} - -var log = Log.repository.getLogger("Identity.FxAccounts"); -log.level = LOG_LEVEL; -log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); - -log.warn("The FxAccountsManager has been removed."); -var FxAccountsManager = null; -var ONVERIFIED_NOTIFICATION = null; -var ONLOGIN_NOTIFICATION = null; -var ONLOGOUT_NOTIFICATION = null; - -function FxAccountsService() { - Services.obs.addObserver(this, "quit-application-granted", false); - if (ONVERIFIED_NOTIFICATION) { - Services.obs.addObserver(this, ONVERIFIED_NOTIFICATION, false); - Services.obs.addObserver(this, ONLOGIN_NOTIFICATION, false); - Services.obs.addObserver(this, ONLOGOUT_NOTIFICATION, false); - } - - // Maintain interface parity with Identity.jsm and MinimalIdentity.jsm - this.RP = this; - - this._rpFlows = new Map(); - - // Enable us to mock FxAccountsManager service in testing - this.fxAccountsManager = FxAccountsManager; -} - -FxAccountsService.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]), - - observe: function observe(aSubject, aTopic, aData) { - switch (aTopic) { - case null: - // Guard against matching null ON*_NOTIFICATION - break; - case ONVERIFIED_NOTIFICATION: - log.debug("Received " + ONVERIFIED_NOTIFICATION + "; firing request()s"); - for (let [rpId,] of this._rpFlows) { - this.request(rpId); - } - break; - case ONLOGIN_NOTIFICATION: - log.debug("Received " + ONLOGIN_NOTIFICATION + "; doLogin()s fired"); - for (let [rpId,] of this._rpFlows) { - this.request(rpId); - } - break; - case ONLOGOUT_NOTIFICATION: - log.debug("Received " + ONLOGOUT_NOTIFICATION + "; doLogout()s fired"); - for (let [rpId,] of this._rpFlows) { - this.doLogout(rpId); - } - break; - case "quit-application-granted": - Services.obs.removeObserver(this, "quit-application-granted"); - if (ONVERIFIED_NOTIFICATION) { - Services.obs.removeObserver(this, ONVERIFIED_NOTIFICATION); - Services.obs.removeObserver(this, ONLOGIN_NOTIFICATION); - Services.obs.removeObserver(this, ONLOGOUT_NOTIFICATION); - } - break; - } - }, - - cleanupRPRequest: function(aRp) { - aRp.pendingRequest = false; - this._rpFlows.set(aRp.id, aRp); - }, - - /** - * Register a listener for a given windowID as a result of a call to - * navigator.id.watch(). - * - * @param aRPCaller - * (Object) an object that represents the caller document, and - * is expected to have properties: - * - id (unique, e.g. uuid) - * - origin (string) - * - * and a bunch of callbacks - * - doReady() - * - doLogin() - * - doLogout() - * - doError() - * - doCancel() - * - */ - watch: function watch(aRpCaller) { - this._rpFlows.set(aRpCaller.id, aRpCaller); - log.debug("watch: " + aRpCaller.id); - log.debug("Current rp flows: " + this._rpFlows.size); - - // Log the user in, if possible, and then call ready(). - let runnable = { - run: () => { - this.fxAccountsManager.getAssertion(aRpCaller.audience, - aRpCaller.principal, - { silent:true }).then( - data => { - if (data) { - this.doLogin(aRpCaller.id, data); - } else { - this.doLogout(aRpCaller.id); - } - this.doReady(aRpCaller.id); - }, - error => { - log.error("get silent assertion failed: " + JSON.stringify(error)); - this.doError(aRpCaller.id, error); - } - ); - } - }; - Services.tm.currentThread.dispatch(runnable, - Ci.nsIThread.DISPATCH_NORMAL); - }, - - /** - * Delete the flow when the screen is unloaded - */ - unwatch: function(aRpCallerId, aTargetMM) { - log.debug("unwatching: " + aRpCallerId); - this._rpFlows.delete(aRpCallerId); - }, - - /** - * Initiate a login with user interaction as a result of a call to - * navigator.id.request(). - * - * @param aRPId - * (integer) the id of the doc object obtained in .watch() - * - * @param aOptions - * (Object) options including privacyPolicy, termsOfService - */ - request: function request(aRPId, aOptions) { - aOptions = aOptions || {}; - let rp = this._rpFlows.get(aRPId); - if (!rp) { - log.error("request() called before watch()"); - return; - } - - // We check if we already have a pending request for this RP and in that - // case we just bail out. We don't want duplicated onlogin or oncancel - // events. - if (rp.pendingRequest) { - log.debug("request() already called"); - return; - } - - // Otherwise, we set the RP flow with the pending request flag. - rp.pendingRequest = true; - this._rpFlows.set(rp.id, rp); - - let options = makeMessageObject(rp); - objectCopy(aOptions, options); - - log.debug("get assertion for " + rp.audience); - - this.fxAccountsManager.getAssertion(rp.audience, rp.principal, options) - .then( - data => { - log.debug("got assertion for " + rp.audience + ": " + data); - this.doLogin(aRPId, data); - }, - error => { - log.debug("get assertion failed: " + JSON.stringify(error)); - // Cancellation is passed through an error channel; here we reroute. - if ((error.error && (error.error.details == "DIALOG_CLOSED_BY_USER")) || - (error.details == "DIALOG_CLOSED_BY_USER")) { - return this.doCancel(aRPId); - } - this.doError(aRPId, error); - } - ) - .then( - () => { - this.cleanupRPRequest(rp); - } - ) - .catch( - () => { - this.cleanupRPRequest(rp); - } - ); - }, - - /** - * Invoked when a user wishes to logout of a site (for instance, when clicking - * on an in-content logout button). - * - * @param aRpCallerId - * (integer) the id of the doc object obtained in .watch() - * - */ - logout: function logout(aRpCallerId) { - // XXX Bug 945363 - Resolve the SSO story for FXA and implement - // logout accordingly. - // - // For now, it makes no sense to logout from a specific RP in - // Firefox Accounts, so just directly call the logout callback. - if (!this._rpFlows.has(aRpCallerId)) { - log.error("logout() called before watch()"); - return; - } - - // Call logout() on the next tick - let runnable = { - run: () => { - this.fxAccountsManager.signOut().then(() => { - this.doLogout(aRpCallerId); - }); - } - }; - Services.tm.currentThread.dispatch(runnable, - Ci.nsIThread.DISPATCH_NORMAL); - }, - - childProcessShutdown: function childProcessShutdown(messageManager) { - for (let [key,] of this._rpFlows) { - if (this._rpFlows.get(key)._mm === messageManager) { - this._rpFlows.delete(key); - } - } - }, - - doLogin: function doLogin(aRpCallerId, aAssertion) { - let rp = this._rpFlows.get(aRpCallerId); - if (!rp) { - log.warn("doLogin found no rp to go with callerId " + aRpCallerId); - return; - } - - rp.doLogin(aAssertion); - }, - - doLogout: function doLogout(aRpCallerId) { - let rp = this._rpFlows.get(aRpCallerId); - if (!rp) { - log.warn("doLogout found no rp to go with callerId " + aRpCallerId); - return; - } - - rp.doLogout(); - }, - - doReady: function doReady(aRpCallerId) { - let rp = this._rpFlows.get(aRpCallerId); - if (!rp) { - log.warn("doReady found no rp to go with callerId " + aRpCallerId); - return; - } - - rp.doReady(); - }, - - doCancel: function doCancel(aRpCallerId) { - let rp = this._rpFlows.get(aRpCallerId); - if (!rp) { - log.warn("doCancel found no rp to go with callerId " + aRpCallerId); - return; - } - - rp.doCancel(); - }, - - doError: function doError(aRpCallerId, aError) { - let rp = this._rpFlows.get(aRpCallerId); - if (!rp) { - log.warn("doError found no rp to go with callerId " + aRpCallerId); - return; - } - - rp.doError(aError); - } -}; - -this.FirefoxAccounts = new FxAccountsService(); - diff --git a/toolkit/identity/moz.build b/toolkit/identity/moz.build index 4c0dc8190e..ba9697bd64 100644 --- a/toolkit/identity/moz.build +++ b/toolkit/identity/moz.build @@ -29,8 +29,4 @@ EXTRA_JS_MODULES.identity += [ 'Sandbox.jsm', ] -EXTRA_PP_JS_MODULES.identity += [ - 'FirefoxAccounts.jsm', -] - FINAL_LIBRARY = 'xul' diff --git a/toolkit/identity/tests/unit/test_firefox_accounts.js b/toolkit/identity/tests/unit/test_firefox_accounts.js deleted file mode 100644 index c0c63deb6f..0000000000 --- a/toolkit/identity/tests/unit/test_firefox_accounts.js +++ /dev/null @@ -1,270 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/DOMIdentity.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAccounts", - "resource://gre/modules/identity/FirefoxAccounts.jsm"); - -// Make the profile dir available; this is necessary so that -// services/fxaccounts/FxAccounts.jsm can read and write its signed-in user -// data. -do_get_profile(); - -function MockFXAManager() { - this.signedInUser = true; -} -MockFXAManager.prototype = { - getAssertion: function(audience) { - let result = this.signedInUser ? TEST_ASSERTION : null; - return Promise.resolve(result); - }, - - signOut: function() { - this.signedInUser = false; - return Promise.resolve(null); - }, - - signIn: function(user) { - this.signedInUser = user; - return Promise.resolve(user); - }, -} - -var originalManager = FirefoxAccounts.fxAccountsManager; -FirefoxAccounts.fxAccountsManager = new MockFXAManager(); -do_register_cleanup(() => { - log("restoring fxaccountsmanager"); - FirefoxAccounts.fxAccountsManager = originalManager; -}); - -function withNobodySignedIn() { - return FirefoxAccounts.fxAccountsManager.signOut(); -} - -function withSomebodySignedIn() { - return FirefoxAccounts.fxAccountsManager.signIn('Pertelote'); -} - -function test_overall() { - do_check_neq(FirefoxAccounts, null); - run_next_test(); -} - -function test_mock() { - do_test_pending(); - - withSomebodySignedIn().then(() => { - FirefoxAccounts.fxAccountsManager.getAssertion().then(assertion => { - do_check_eq(assertion, TEST_ASSERTION); - do_test_finished(); - run_next_test(); - }); - }); -} - -function test_watch_signed_in() { - do_test_pending(); - - let received = []; - - let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) { - received.push([method, data]); - - if (method == "ready") { - // confirm that we were signed in and then ready was called - do_check_eq(received.length, 2); - do_check_eq(received[0][0], "login"); - do_check_eq(received[0][1], TEST_ASSERTION); - do_check_eq(received[1][0], "ready"); - do_test_finished(); - run_next_test(); - } - }); - - withSomebodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); -} - -function test_watch_signed_out() { - do_test_pending(); - - let received = []; - - let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) { - received.push(method); - - if (method == "ready") { - // confirm that we were signed out and then ready was called - do_check_eq(received.length, 2); - do_check_eq(received[0], "logout"); - do_check_eq(received[1], "ready"); - - do_test_finished(); - run_next_test(); - } - }); - - withNobodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); -} - -function test_request() { - do_test_pending(); - - let received = []; - - let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) { - received.push([method, data]); - - // On watch(), we are signed out. Then we call request(). - if (received.length === 2) { - do_check_eq(received[0][0], "logout"); - do_check_eq(received[1][0], "ready"); - - // Pretend request() showed ux and the user signed in - withSomebodySignedIn().then(() => { - FirefoxAccounts.RP.request(mockedRP.id); - }); - } - - if (received.length === 3) { - do_check_eq(received[2][0], "login"); - do_check_eq(received[2][1], TEST_ASSERTION); - - do_test_finished(); - run_next_test(); - } - }); - - // First, call watch() with nobody signed in - withNobodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); -} - -function test_logout() { - do_test_pending(); - - let received = []; - - let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) { - received.push(method); - - // At first, watch() signs us in automatically. Then we sign out. - if (received.length === 2) { - do_check_eq(received[0], "login"); - do_check_eq(received[1], "ready"); - - FirefoxAccounts.RP.logout(mockedRP.id); - } - - if (received.length === 3) { - do_check_eq(received[2], "logout"); - do_test_finished(); - run_next_test(); - } - }); - - // First, call watch() - withSomebodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); -} - -function test_error() { - do_test_pending(); - - let received = []; - - // Mock the fxAccountsManager so that getAssertion rejects its promise and - // triggers our onerror handler. (This is the method that's used internally - // by FirefoxAccounts.RP.request().) - let originalGetAssertion = FirefoxAccounts.fxAccountsManager.getAssertion; - FirefoxAccounts.fxAccountsManager.getAssertion = function(audience) { - return Promise.reject(new Error("barf!")); - }; - - let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, message) { - // We will immediately receive an error, due to watch()'s attempt - // to getAssertion(). - do_check_eq(method, "error"); - do_check_true(/barf/.test(message)); - - // Put things back the way they were - FirefoxAccounts.fxAccountsManager.getAssertion = originalGetAssertion; - - do_test_finished(); - run_next_test(); - }); - - // First, call watch() - withSomebodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); -} - -function test_child_process_shutdown() { - do_test_pending(); - let rpCount = FirefoxAccounts.RP._rpFlows.size; - - makeObserver("identity-child-process-shutdown", (aTopic, aSubject, aData) => { - // Last of all, the shutdown observer message will be fired. - // This takes place after the RP has a chance to delete flows - // and clean up. - do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount); - do_test_finished(); - run_next_test(); - }); - - let mockedRP = mock_fxa_rp(null, TEST_URL, (method) => { - // We should enter this function for 'ready' and 'child-process-shutdown'. - // After we have a chance to do our thing, the shutdown observer message - // will fire and be caught by the function above. - do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount + 1); - switch (method) { - case "ready": - DOMIdentity._childProcessShutdown("my message manager"); - break; - - case "child-process-shutdown": - // We have to call this explicitly because there's no real - // dom window here. - FirefoxAccounts.RP.childProcessShutdown(mockedRP._mm); - break; - - default: - break; - } - }); - - mockedRP._mm = "my message manager"; - withSomebodySignedIn().then(() => { - FirefoxAccounts.RP.watch(mockedRP); - }); - - // fake a dom window context - DOMIdentity.newContext(mockedRP, mockedRP._mm); -} - -var TESTS = [ - test_overall, - test_mock, - test_watch_signed_in, - test_watch_signed_out, - test_request, - test_logout, - test_error, - test_child_process_shutdown, -]; - -TESTS.forEach(add_test); - -function run_test() { - run_next_test(); -} diff --git a/toolkit/identity/tests/unit/xpcshell.ini b/toolkit/identity/tests/unit/xpcshell.ini index 38b37402c9..309e4791c9 100644 --- a/toolkit/identity/tests/unit/xpcshell.ini +++ b/toolkit/identity/tests/unit/xpcshell.ini @@ -9,7 +9,6 @@ support-files = # Test load modules first so syntax failures are caught early. [test_load_modules.js] [test_minimalidentity.js] -[test_firefox_accounts.js] [test_identity_utils.js] [test_log_utils.js] diff --git a/tools/lint/eslint/modules.json b/tools/lint/eslint/modules.json index 767b43db08..158ba5fe6a 100644 --- a/tools/lint/eslint/modules.json +++ b/tools/lint/eslint/modules.json @@ -82,15 +82,6 @@ "forms.jsm": ["FormData"], "frame.js": ["Collector", "Runner", "events", "runTestFile", "log", "timers", "persisted", "shutdownApplication"], "FrameScriptManager.jsm": ["getNewLoaderID"], - "fxa_utils.js": ["initializeIdentityWithTokenServerResponse"], - "fxaccounts.jsm": ["Authentication"], - "FxAccounts.jsm": ["fxAccounts", "FxAccounts"], - "FxAccountsOAuthGrantClient.jsm": ["FxAccountsOAuthGrantClient", "FxAccountsOAuthGrantClientError"], - "FxAccountsProfileClient.jsm": ["FxAccountsProfileClient", "FxAccountsProfileClientError"], - "FxAccountsPush.js": ["FxAccountsPushService"], - "FxAccountsStorage.jsm": ["FxAccountsStorageManagerCanStoreField", "FxAccountsStorageManager"], - "FxAccountsWebChannel.jsm": ["EnsureFxAccountsWebChannel"], - "FxaMigrator.jsm": ["fxaMigrator"], "gDevTools.jsm": ["gDevTools", "gDevToolsBrowser"], "gDevTools.jsm": ["gDevTools", "gDevToolsBrowser"], "Geometry.jsm": ["Point", "Rect"], |