diff options
Diffstat (limited to 'services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js')
-rw-r--r-- | services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js b/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js new file mode 100644 index 0000000000..7abbd0e44a --- /dev/null +++ b/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js @@ -0,0 +1,314 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests for FxAccounts, storage and the master password. + +// See verbose logging from FxAccounts.jsm +Services.prefs.setCharPref("identity.fxaccounts.loglevel", "Trace"); + +const { FxAccounts } = ChromeUtils.importESModule( + "resource://gre/modules/FxAccounts.sys.mjs" +); +const { FXA_PWDMGR_HOST, FXA_PWDMGR_REALM } = ChromeUtils.import( + "resource://gre/modules/FxAccountsCommon.js" +); + +// Use a backstage pass to get at our LoginManagerStorage object, so we can +// mock the prototype. +var { LoginManagerStorage } = ChromeUtils.importESModule( + "resource://gre/modules/FxAccountsStorage.sys.mjs" +); +var isLoggedIn = true; +LoginManagerStorage.prototype.__defineGetter__("_isLoggedIn", () => isLoggedIn); + +function setLoginMgrLoggedInState(loggedIn) { + isLoggedIn = loggedIn; +} + +initTestLogging("Trace"); + +function getLoginMgrData() { + let logins = Services.logins.findLogins( + FXA_PWDMGR_HOST, + null, + FXA_PWDMGR_REALM + ); + if (!logins.length) { + return null; + } + Assert.equal(logins.length, 1, "only 1 login available"); + return logins[0]; +} + +function createFxAccounts() { + return new FxAccounts({ + _fxAccountsClient: { + async registerDevice() { + return { id: "deviceAAAAAA" }; + }, + async recoveryEmailStatus() { + return { verified: true }; + }, + async signOut() {}, + }, + updateDeviceRegistration() {}, + _getDeviceName() { + return "mock device name"; + }, + observerPreloads: [], + fxaPushService: { + async registerPushEndpoint() { + return { + endpoint: "http://mochi.test:8888", + getKey() { + return null; + }, + }; + }, + async unsubscribe() { + return true; + }, + }, + }); +} + +add_task(async function test_simple() { + let fxa = createFxAccounts(); + + let creds = { + uid: "abcd", + email: "test@example.com", + sessionToken: "sessionToken", + kSync: "the kSync value", + kXCS: "the kXCS value", + kExtSync: "the kExtSync value", + kExtKbHash: "the kExtKbHash value", + verified: true, + }; + await fxa._internal.setSignedInUser(creds); + + // This should have stored stuff in both the .json file in the profile + // dir, and the login dir. + let path = PathUtils.join(PathUtils.profileDir, "signedInUser.json"); + let data = await IOUtils.readJSON(path); + + Assert.strictEqual( + data.accountData.email, + creds.email, + "correct email in the clear text" + ); + Assert.strictEqual( + data.accountData.sessionToken, + creds.sessionToken, + "correct sessionToken in the clear text" + ); + Assert.strictEqual( + data.accountData.verified, + creds.verified, + "correct verified flag" + ); + + Assert.ok(!("kSync" in data.accountData), "kSync not stored in clear text"); + Assert.ok(!("kXCS" in data.accountData), "kXCS not stored in clear text"); + Assert.ok( + !("kExtSync" in data.accountData), + "kExtSync not stored in clear text" + ); + Assert.ok( + !("kExtKbHash" in data.accountData), + "kExtKbHash not stored in clear text" + ); + + let login = getLoginMgrData(); + Assert.strictEqual(login.username, creds.uid, "uid used for username"); + let loginData = JSON.parse(login.password); + Assert.strictEqual( + loginData.version, + data.version, + "same version flag in both places" + ); + Assert.strictEqual( + loginData.accountData.kSync, + creds.kSync, + "correct kSync in the login mgr" + ); + Assert.strictEqual( + loginData.accountData.kXCS, + creds.kXCS, + "correct kXCS in the login mgr" + ); + Assert.strictEqual( + loginData.accountData.kExtSync, + creds.kExtSync, + "correct kExtSync in the login mgr" + ); + Assert.strictEqual( + loginData.accountData.kExtKbHash, + creds.kExtKbHash, + "correct kExtKbHash in the login mgr" + ); + + Assert.ok(!("email" in loginData), "email not stored in the login mgr json"); + Assert.ok( + !("sessionToken" in loginData), + "sessionToken not stored in the login mgr json" + ); + Assert.ok( + !("verified" in loginData), + "verified not stored in the login mgr json" + ); + + await fxa.signOut(/* localOnly = */ true); + Assert.strictEqual( + getLoginMgrData(), + null, + "login mgr data deleted on logout" + ); +}); + +add_task(async function test_MPLocked() { + let fxa = createFxAccounts(); + + let creds = { + uid: "abcd", + email: "test@example.com", + sessionToken: "sessionToken", + kSync: "the kSync value", + kXCS: "the kXCS value", + kExtSync: "the kExtSync value", + kExtKbHash: "the kExtKbHash value", + verified: true, + }; + + Assert.strictEqual(getLoginMgrData(), null, "no login mgr at the start"); + // tell the storage that the MP is locked. + setLoginMgrLoggedInState(false); + await fxa._internal.setSignedInUser(creds); + + // This should have stored stuff in the .json, and the login manager stuff + // will not exist. + let path = PathUtils.join(PathUtils.profileDir, "signedInUser.json"); + let data = await IOUtils.readJSON(path); + + Assert.strictEqual( + data.accountData.email, + creds.email, + "correct email in the clear text" + ); + Assert.strictEqual( + data.accountData.sessionToken, + creds.sessionToken, + "correct sessionToken in the clear text" + ); + Assert.strictEqual( + data.accountData.verified, + creds.verified, + "correct verified flag" + ); + + Assert.ok(!("kSync" in data.accountData), "kSync not stored in clear text"); + Assert.ok(!("kXCS" in data.accountData), "kXCS not stored in clear text"); + Assert.ok( + !("kExtSync" in data.accountData), + "kExtSync not stored in clear text" + ); + Assert.ok( + !("kExtKbHash" in data.accountData), + "kExtKbHash not stored in clear text" + ); + + Assert.strictEqual(getLoginMgrData(), null, "login mgr data doesn't exist"); + await fxa.signOut(/* localOnly = */ true); +}); + +add_task(async function test_consistentWithMPEdgeCases() { + setLoginMgrLoggedInState(true); + + let fxa = createFxAccounts(); + + let creds1 = { + uid: "uid1", + email: "test@example.com", + sessionToken: "sessionToken", + kSync: "the kSync value", + kXCS: "the kXCS value", + kExtSync: "the kExtSync value", + kExtKbHash: "the kExtKbHash value", + verified: true, + }; + + let creds2 = { + uid: "uid2", + email: "test2@example.com", + sessionToken: "sessionToken2", + kSync: "the kSync value2", + kXCS: "the kXCS value2", + kExtSync: "the kExtSync value2", + kExtKbHash: "the kExtKbHash value2", + verified: false, + }; + + // Log a user in while MP is unlocked. + await fxa._internal.setSignedInUser(creds1); + + // tell the storage that the MP is locked - this will prevent logout from + // being able to clear the data. + setLoginMgrLoggedInState(false); + + // now set the second credentials. + await fxa._internal.setSignedInUser(creds2); + + // We should still have creds1 data in the login manager. + let login = getLoginMgrData(); + Assert.strictEqual(login.username, creds1.uid); + // and that we do have the first kSync in the login manager. + Assert.strictEqual( + JSON.parse(login.password).accountData.kSync, + creds1.kSync, + "stale data still in login mgr" + ); + + // Make a new FxA instance (otherwise the values in memory will be used) + // and we want the login manager to be unlocked. + setLoginMgrLoggedInState(true); + fxa = createFxAccounts(); + + let accountData = await fxa.getSignedInUser(); + Assert.strictEqual(accountData.email, creds2.email); + // we should have no kSync at all. + Assert.strictEqual(accountData.kSync, undefined, "stale kSync wasn't used"); + await fxa.signOut(/* localOnly = */ true); +}); + +// A test for the fact we will accept either a UID or email when looking in +// the login manager. +add_task(async function test_uidMigration() { + setLoginMgrLoggedInState(true); + Assert.strictEqual(getLoginMgrData(), null, "expect no logins at the start"); + + // create the login entry using email as a key. + let contents = { kSync: "kSync" }; + + let loginInfo = new Components.Constructor( + "@mozilla.org/login-manager/loginInfo;1", + Ci.nsILoginInfo, + "init" + ); + let login = new loginInfo( + FXA_PWDMGR_HOST, + null, // aFormActionOrigin, + FXA_PWDMGR_REALM, // aHttpRealm, + "foo@bar.com", // aUsername + JSON.stringify(contents), // aPassword + "", // aUsernameField + "" + ); // aPasswordField + await Services.logins.addLoginAsync(login); + + // ensure we read it. + let storage = new LoginManagerStorage(); + let got = await storage.get("uid", "foo@bar.com"); + Assert.deepEqual(got, contents); +}); |