tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 5cf58523f9e256cf891eb2571440f809c736840d
parent fd4a2206bc3b15f9f118e77c8a4bb32239922324
Author: Mark Hammond <mhammond@skippinet.com.au>
Date:   Tue, 16 Dec 2025 00:22:08 +0000

Bug 1928073 - Use the account uid for all FxA merge warnings. r=skhamis,sync-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D270858

Diffstat:
Mbrowser/base/content/test/sync/browser_fxa_web_channel.html | 1+
Mbrowser/base/content/test/sync/browser_fxa_web_channel.js | 15+++++++++++----
Mservices/fxaccounts/FxAccounts.sys.mjs | 27+++++++++++++++++----------
Mservices/fxaccounts/FxAccountsCommon.sys.mjs | 8+++++++-
Mservices/fxaccounts/FxAccountsWebChannel.sys.mjs | 120+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mservices/fxaccounts/tests/xpcshell/test_sync_warning_dialogs.js | 58++++++++++++++++++++++++++++++++++++++++++++--------------
Mservices/fxaccounts/tests/xpcshell/test_web_channel.js | 86++++++++++++++++++++++++++++---------------------------------------------------
Mservices/sync/modules/SyncDisconnect.sys.mjs | 6++++--
Mservices/sync/tests/unit/test_disconnect_shutdown.js | 9++++++---
9 files changed, 197 insertions(+), 133 deletions(-)

diff --git a/browser/base/content/test/sync/browser_fxa_web_channel.html b/browser/base/content/test/sync/browser_fxa_web_channel.html @@ -93,6 +93,7 @@ message: { command: "fxaccounts:can_link_account", data: { + uid: "uid", email: "testuser@testuser.com", }, messageId: 2, diff --git a/browser/base/content/test/sync/browser_fxa_web_channel.js b/browser/base/content/test/sync/browser_fxa_web_channel.js @@ -117,13 +117,20 @@ var gTests = [ content_uri: TEST_HTTP_PATH, channel_id: TEST_CHANNEL_ID, helpers: { - shouldAllowRelink(acctName) { - return acctName === "testuser@testuser.com"; + shouldAllowRelink(acctData) { + if (acctData.uid == "uid") { + Assert.equal(acctData.email, "testuser@testuser.com"); + return true; + } + Assert.notEqual(acctData.email, "testuser@testuser.com"); + return false; }, - promptProfileSyncWarningIfNeeded(acctName) { - if (acctName === "testuser@testuser.com") { + promptProfileSyncWarningIfNeeded(acctData) { + if (acctData.uid == "uid") { + Assert.equal(acctData.email, "testuser@testuser.com"); return { action: "continue" }; } + Assert.notEqual(acctData.email, "testuser@testuser.com"); return { action: "cancel" }; }, }, diff --git a/services/fxaccounts/FxAccounts.sys.mjs b/services/fxaccounts/FxAccounts.sys.mjs @@ -2,7 +2,6 @@ * 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/. */ -import { CryptoUtils } from "moz-src:///services/crypto/modules/utils.sys.mjs"; import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; import { FxAccountsStorageManager } from "resource://gre/modules/FxAccountsStorage.sys.mjs"; @@ -28,7 +27,8 @@ import { ON_DEVICE_DISCONNECTED_NOTIFICATION, POLL_SESSION, PREF_ACCOUNT_ROOT, - PREF_LAST_FXA_USER, + PREF_LAST_FXA_USER_EMAIL, + PREF_LAST_FXA_USER_UID, SERVER_ERRNO_TO_ERROR, log, logPII, @@ -38,6 +38,7 @@ import { const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { + CryptoUtils: "moz-src:///services/crypto/modules/utils.sys.mjs", FxAccountsClient: "resource://gre/modules/FxAccountsClient.sys.mjs", FxAccountsCommands: "resource://gre/modules/FxAccountsCommands.sys.mjs", FxAccountsConfig: "resource://gre/modules/FxAccountsConfig.sys.mjs", @@ -1111,6 +1112,19 @@ FxAccountsInternal.prototype = { return Promise.all(promises); }, + // We need to do a one-off migration of a preference to protect against + // accidentally merging sync data. + // We replace a previously hashed email with a hashed uid. + _migratePreviousAccountNameHashPref(uid) { + if (Services.prefs.prefHasUserValue(PREF_LAST_FXA_USER_EMAIL)) { + Services.prefs.setStringPref( + PREF_LAST_FXA_USER_UID, + lazy.CryptoUtils.sha256Base64(uid) + ); + Services.prefs.clearUserPref(PREF_LAST_FXA_USER_EMAIL); + } + }, + async signOut(localOnly) { let sessionToken; let tokensToRevoke; @@ -1119,6 +1133,7 @@ FxAccountsInternal.prototype = { if (data) { sessionToken = data.sessionToken; tokensToRevoke = data.oauthTokens; + this._migratePreviousAccountNameHashPref(data.uid); } await this.notifyObservers(ON_PRELOGOUT_NOTIFICATION); await this._signOutLocal(); @@ -1361,15 +1376,7 @@ FxAccountsInternal.prototype = { await this.notifyObservers(ON_DEVICE_DISCONNECTED_NOTIFICATION, data); }, - _setLastUserPref(newEmail) { - Services.prefs.setStringPref( - PREF_LAST_FXA_USER, - CryptoUtils.sha256Base64(newEmail) - ); - }, - async _handleEmailUpdated(newEmail) { - this._setLastUserPref(newEmail); await this.currentAccountState.updateUserAccountData({ email: newEmail }); }, diff --git a/services/fxaccounts/FxAccountsCommon.sys.mjs b/services/fxaccounts/FxAccountsCommon.sys.mjs @@ -151,7 +151,13 @@ export let COMMAND_FIREFOX_VIEW = "fxaccounts:firefox_view"; // be stored. This branch will be reset on account signout and signin. export let PREF_ACCOUNT_ROOT = "identity.fxaccounts.account."; -export let PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash"; +// Where we store the hashed uid of the previous user. +export let PREF_LAST_FXA_USER_UID = + "identity.fxaccounts.lastSignedInUserIdHash"; +// Where we used to store the hashed email of the previous user. We now store the +// uid, but need to migrate from this. +export let PREF_LAST_FXA_USER_EMAIL = + "identity.fxaccounts.lastSignedInUserHash"; export let PREF_REMOTE_PAIRING_URI = "identity.fxaccounts.remote.pairing.uri"; // Server errno. diff --git a/services/fxaccounts/FxAccountsWebChannel.sys.mjs b/services/fxaccounts/FxAccountsWebChannel.sys.mjs @@ -30,7 +30,8 @@ import { COMMAND_FIREFOX_VIEW, OAUTH_CLIENT_ID, ON_PROFILE_CHANGE_NOTIFICATION, - PREF_LAST_FXA_USER, + PREF_LAST_FXA_USER_UID, + PREF_LAST_FXA_USER_EMAIL, WEBCHANNEL_ID, log, logPII, @@ -300,16 +301,15 @@ FxAccountsWebChannel.prototype = { { let response = { command, messageId: message.messageId }; // If browser profiles are not enabled, then we use the old merge sync dialog - if (!lazy.SelectableProfileService?.isEnabled) { - response.data = { ok: this._helpers.shouldAllowRelink(data.email) }; + if (!this._helpers._selectableProfilesEnabled()) { + response.data = { ok: this._helpers.shouldAllowRelink(data) }; this._channel.send(response, sendingContext); break; } // In the new sync warning, we give users a few more options to // control what they want to do with their sync data - let result = await this._helpers.promptProfileSyncWarningIfNeeded( - data.email - ); + let result = + await this._helpers.promptProfileSyncWarningIfNeeded(data); switch (result.action) { case "create-profile": lazy.SelectableProfileService.createNewProfile(); @@ -517,9 +517,10 @@ FxAccountsWebChannelHelpers.prototype = { // (This is sync-specific, so ideally would be in sync's identity module, // but it's a little more seamless to do here, and sync is currently the // only fxa consumer, so... - shouldAllowRelink(acctName) { + shouldAllowRelink(acctData) { return ( - !this._needRelinkWarning(acctName) || this._promptForRelink(acctName) + !this._needRelinkWarning(acctData) || + this._promptForRelink(acctData.email) ); }, @@ -530,14 +531,15 @@ FxAccountsWebChannelHelpers.prototype = { * @returns {string} - The corresponding option the user pressed. Can be either: * cancel, continue, switch-profile, or create-profile */ - async promptProfileSyncWarningIfNeeded(acctEmail) { + async promptProfileSyncWarningIfNeeded(acctData) { // Was a previous account signed into this profile or is there another profile currently signed in // to the account we're signing into - let profileLinkedWithAcct = - await this._getProfileAssociatedWithAcct(acctEmail); - if (this._needRelinkWarning(acctEmail) || profileLinkedWithAcct) { + let profileLinkedWithAcct = acctData.uid + ? await this._getProfileAssociatedWithAcct(acctData.uid) + : null; + if (this._needRelinkWarning(acctData) || profileLinkedWithAcct) { return this._promptForProfileSyncWarning( - acctEmail, + acctData.email, profileLinkedWithAcct ); } @@ -664,23 +666,22 @@ FxAccountsWebChannelHelpers.prototype = { log.debug(`storing info for services ${Object.keys(requestedServices)}`); accountData.requestedServices = JSON.stringify(requestedServices); - this.setPreviousAccountNameHashPref(accountData.email); + this.setPreviousAccountHashPref(accountData.uid); await this._fxAccounts._internal.setSignedInUser(accountData); log.debug("Webchannel finished logging a user in."); }, /** - * Logins in to sync by completing an OAuth flow + * Logs in to sync by completing an OAuth flow * * @param {object} oauthData: The oauth code and state as returned by the server */ async oauthLogin(oauthData) { log.debug("Webchannel is completing the oauth flow"); - const { uid, sessionToken, email, requestedServices } = + const { uid, sessionToken, requestedServices } = await this._fxAccounts._internal.getUserAccountData([ "uid", "sessionToken", - "email", "requestedServices", ]); // First we finish the ongoing oauth flow @@ -695,7 +696,7 @@ FxAccountsWebChannelHelpers.prototype = { await this._fxAccounts._internal.destroyOAuthToken({ token: refreshToken }); // Remember the account for future merge warnings etc. - this.setPreviousAccountNameHashPref(email); + this.setPreviousAccountHashPref(uid); if (!scopedKeys) { log.info( @@ -855,6 +856,7 @@ FxAccountsWebChannelHelpers.prototype = { // This capability is for telling FxA that the current build can accept // accounts without passwords/sync keys (third-party auth) keys_optional: true, + can_link_account_uid: true, engines, }; }, @@ -890,26 +892,22 @@ FxAccountsWebChannelHelpers.prototype = { }, /** - * Get the hash of account name of the previously signed in account - */ - getPreviousAccountNameHashPref() { - try { - return Services.prefs.getStringPref(PREF_LAST_FXA_USER); - } catch (_) { - return ""; - } - }, - - /** - * Given an account name, set the hash of the previously signed in account + * Remember that a particular account id was previously signed in to this device. * - * @param acctName the account name of the user's account. + * @param uid the account uid */ - setPreviousAccountNameHashPref(acctName) { + setPreviousAccountHashPref(uid) { + if (!uid) { + throw new Error("No uid specified"); + } Services.prefs.setStringPref( - PREF_LAST_FXA_USER, - lazy.CryptoUtils.sha256Base64(acctName) + PREF_LAST_FXA_USER_UID, + lazy.CryptoUtils.sha256Base64(uid) ); + // This should not be necessary but exists just to be safe, to avoid + // any possibility we somehow end up with *both* prefs set and each indicating + // a different account. + Services.prefs.clearUserPref(PREF_LAST_FXA_USER_EMAIL); }, /** @@ -946,10 +944,46 @@ FxAccountsWebChannelHelpers.prototype = { * * @private */ - _needRelinkWarning(acctName) { - let prevAcctHash = this.getPreviousAccountNameHashPref(); + _needRelinkWarning(acctData) { + // This code *never* expects both PREF_LAST_FXA_USER_EMAIL and PREF_LAST_FXA_USER_UID. + // * If we have PREF_LAST_FXA_USER_EMAIL it means we were signed out before we migrated + // to UID, and can't learn that UID, so have no UID pref set. + // * If the UID pref exists, our code since that landed will never write to the + // PREF_LAST_FXA_USER_EMAIL pref. + // The only way both could be true would be something catastrophic, such as our + // "migrate to uid at sign-out" code somehow died between writing the UID and + // clearing the email. + // + // Therefore, we don't even try to handle both being set, but do prefer the UID + // because that must have been written by the new code paths introduced for that pref. + const lastUid = Services.prefs.getStringPref(PREF_LAST_FXA_USER_UID, ""); + if (lastUid) { + // A special case here is for when no uid is specified by the server - that means the + // server is about to create a new account. Therefore, the new account can't possibly + // match. + return ( + !acctData.uid || lastUid != lazy.CryptoUtils.sha256Base64(acctData.uid) + ); + } + + // no uid pref, check if there's an EMAIL pref (which means a user previously signed out + // before we landed this uid-aware code, so only know their email.) + const lastEmail = Services.prefs.getStringPref( + PREF_LAST_FXA_USER_EMAIL, + "" + ); + return ( + lastEmail && lastEmail != lazy.CryptoUtils.sha256Base64(acctData.email) + ); + }, + + // Does this install have multiple profiles available? The SelectableProfileService + // being enabled isn't enough, because this doesn't tell us whether a new profile + // as actually created! + _selectableProfilesEnabled() { return ( - prevAcctHash && prevAcctHash != lazy.CryptoUtils.sha256Base64(acctName) + lazy.SelectableProfileService?.isEnabled && + lazy.SelectableProfileService?.hasCreatedSelectableProfiles() ); }, @@ -965,10 +999,10 @@ FxAccountsWebChannelHelpers.prototype = { /** * Checks if a profile is associated with the given account email. * - * @param {string} acctEmail - The email of the account to check. + * @param {string} acctUid - The uid of the account to check. * @returns {Promise<SelectableProfile|null>} - The profile associated with the account, or null if none. */ - async _getProfileAssociatedWithAcct(acctEmail) { + async _getProfileAssociatedWithAcct(acctUid) { let profiles = await this._getAllProfiles(); let currentProfileName = await this._getCurrentProfileName(); for (let profile of profiles) { @@ -981,7 +1015,7 @@ FxAccountsWebChannelHelpers.prototype = { let signedInUser = await this._readJSONFileAsync(signedInUserPath); if ( signedInUser?.accountData && - signedInUser.accountData.email === acctEmail + signedInUser.accountData.uid === acctUid ) { // The account is signed into another profile return profile; @@ -1012,7 +1046,7 @@ FxAccountsWebChannelHelpers.prototype = { * * @private */ - _promptForRelink(acctName) { + _promptForRelink(acctEmail) { let [continueLabel, title, heading, description] = lazy.l10n.formatValuesSync([ { id: "sync-setup-verify-continue" }, @@ -1021,7 +1055,7 @@ FxAccountsWebChannelHelpers.prototype = { { id: "sync-setup-verify-description", args: { - email: acctName, + email: acctEmail, }, }, ]); @@ -1242,7 +1276,7 @@ FxAccountsWebChannelHelpers.prototype = { ) { let variant; - if (!lazy.SelectableProfileService?.isEnabled) { + if (!this._selectableProfilesEnabled()) { // Old merge dialog variant = "old-merge"; } else if (isAccountLoggedIntoAnotherProfile) { diff --git a/services/fxaccounts/tests/xpcshell/test_sync_warning_dialogs.js b/services/fxaccounts/tests/xpcshell/test_sync_warning_dialogs.js @@ -8,6 +8,7 @@ ChromeUtils.defineESModuleGetters(this, { "resource://gre/modules/FxAccountsWebChannel.sys.mjs", SelectableProfileService: "resource:///modules/profiles/SelectableProfileService.sys.mjs", + PREF_LAST_FXA_USER_UID: "resource://gre/modules/FxAccountsCommon.sys.mjs", }); // Set up mocked profiles @@ -124,7 +125,7 @@ add_task( let helpers = new FxAccountsWebChannelHelpers(); // We "pretend" there was another account previously logged in - helpers.setPreviousAccountNameHashPref("testuser@testuser.com"); + helpers.setPreviousAccountHashPref("test_uid"); // Mock methods helpers._getAllProfiles = async () => mockedProfiles; @@ -145,9 +146,11 @@ add_task( variant.expectedResponses[i]; gResponse = responseVal; - let result = - await helpers.promptProfileSyncWarningIfNeeded("testuser2@test.com"); - //Verify we returned the expected result + let result = await helpers.promptProfileSyncWarningIfNeeded({ + email: "testuser2@test.com", + uid: "test2", + }); + // Verify we returned the expected result Assert.deepEqual(result, expectedResult); let gleanValue = Glean.syncMergeDialog.clicked.testGetValue(); @@ -273,7 +276,7 @@ add_task( // The account is signed into the other profile return { version: 1, - accountData: { email: "testuser2@test.com" }, + accountData: { email: "testuser2@test.com", uid: "uid" }, }; } return null; @@ -291,9 +294,11 @@ add_task( variant.expectedResponses[i]; gResponse = responseVal; - let result = - await helpers.promptProfileSyncWarningIfNeeded("testuser2@test.com"); - //Verify we returned the expected result + let result = await helpers.promptProfileSyncWarningIfNeeded({ + email: "testuser2@test.com", + uid: "uid", + }); + // Verify we returned the expected result Assert.deepEqual(result, expectedResult); let gleanValue = Glean.syncMergeDialog.clicked.testGetValue(); @@ -331,11 +336,11 @@ add_task(async function test_current_profile_is_correctly_skipped() { // Profile2 is signed in with other@example.com. const fakeSignedInUsers = { [PathUtils.join(PathUtils.tempDir, "profile1", "signedInUser.json")]: { - accountData: { email: "user@example.com" }, + accountData: { email: "user@example.com", uid: "user" }, version: 1, }, [PathUtils.join(PathUtils.tempDir, "profile2", "signedInUser.json")]: { - accountData: { email: "other@example.com" }, + accountData: { email: "other@example.com", uid: "other" }, version: 1, }, }; @@ -350,8 +355,7 @@ add_task(async function test_current_profile_is_correctly_skipped() { fakeSignedInUsers[filePath] || null; // Case 1: The account email is in the current profile. - let associatedProfile = - await channel._getProfileAssociatedWithAcct("user@example.com"); + let associatedProfile = await channel._getProfileAssociatedWithAcct("user"); Assert.equal( associatedProfile, null, @@ -359,8 +363,7 @@ add_task(async function test_current_profile_is_correctly_skipped() { ); // Case 2: The account email is in a different profile. - associatedProfile = - await channel._getProfileAssociatedWithAcct("other@example.com"); + associatedProfile = await channel._getProfileAssociatedWithAcct("other"); Assert.ok( associatedProfile, "Should return a profile when account email is in another profile." @@ -371,3 +374,30 @@ add_task(async function test_current_profile_is_correctly_skipped() { "Returned profile should be 'Profile2'." ); }); + +// Test need-relink-warning. +add_task( + async function test_previously_signed_in_dialog_variants_result_and_telemetry() { + let helpers = new FxAccountsWebChannelHelpers(); + + // We "pretend" there was another account previously logged in + helpers.setPreviousAccountHashPref("test_uid"); + + Assert.ok( + !helpers._needRelinkWarning({ + email: "testuser2@test.com", + uid: "test_uid", + }) + ); + Assert.ok( + helpers._needRelinkWarning({ + email: "testuser2@test.com", + uid: "different_uid", + }) + ); + // missing uid == "new account" == "always need the warning if anyone was previously logged in" + Assert.ok(helpers._needRelinkWarning({ email: "testuser2@test.com" })); + Services.prefs.clearUserPref(PREF_LAST_FXA_USER_UID); + Assert.ok(!helpers._needRelinkWarning({ email: "testuser2@test.com" })); + } +); diff --git a/services/fxaccounts/tests/xpcshell/test_web_channel.js b/services/fxaccounts/tests/xpcshell/test_web_channel.js @@ -13,6 +13,9 @@ const { FxAccountsWebChannel, FxAccountsWebChannelHelpers } = "resource://gre/modules/FxAccountsWebChannel.sys.mjs" ); +const { PREF_LAST_FXA_USER_EMAIL, PREF_LAST_FXA_USER_UID } = + ChromeUtils.importESModule("resource://gre/modules/FxAccountsCommon.sys.mjs"); + const URL_STRING = "https://example.com"; const mockSendingContext = { @@ -63,7 +66,7 @@ add_task(async function test_rejection_reporting() { let mockMessage = { command: "fxaccounts:login", messageId: "1234", - data: { email: "testuser@testuser.com" }, + data: { email: "testuser@testuser.com", uid: "testuser" }, }; let channel = new FxAccountsWebChannel({ @@ -332,19 +335,15 @@ add_test(function test_delete_message() { add_test(function test_can_link_account_message() { let mockMessage = { command: "fxaccounts:can_link_account", - data: { email: "testuser@testuser.com" }, + data: { email: "testuser@testuser.com", uid: "testuser" }, }; let channel = new FxAccountsWebChannel({ channel_id: WEBCHANNEL_ID, content_uri: URL_STRING, helpers: { - shouldAllowRelink(email) { - Assert.equal(email, "testuser@testuser.com"); - run_next_test(); - }, - promptProfileSyncWarningIfNeeded(acctName) { - Assert.equal(acctName, "testuser@testuser.com"); + shouldAllowRelink(acctData) { + Assert.deepEqual(acctData, mockMessage.data); run_next_test(); }, }, @@ -435,45 +434,7 @@ add_test(function test_fxa_status_message() { channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext); }); -add_test(function test_respond_to_device_commands() { - let mockMessageLoggedOut = { - command: "fxaccounts:logout", - messageId: 123, - data: {}, - }; - let mockMessageLoggedIn = { - command: "fxaccounts:login", - messageId: 123, - data: {}, - }; - - let channel = new FxAccountsWebChannel({ - channel_id: WEBCHANNEL_ID, - content_uri: URL_STRING, - }); - channel._channel = { - send(response) { - Assert.ok(!!response.data); - Assert.equal(response.data.ok, true); - - run_next_test(); - }, - }; - - channel._channelCallback( - WEBCHANNEL_ID, - mockMessageLoggedOut, - mockSendingContext - ); - - channel._channelCallback( - WEBCHANNEL_ID, - mockMessageLoggedIn, - mockSendingContext - ); -}); - -add_test(function test_respond_to_incorrect_device_commands() { +add_test(function test_respond_to_invalid_commands() { let mockMessageLogout = { command: "fxaccounts:lagaut", // intentional typo. messageId: 123, @@ -517,11 +478,16 @@ add_test(function test_unrecognized_message() { run_next_test(); }); -add_test(function test_helpers_should_allow_relink_same_email() { +add_test(function test_helpers_should_allow_relink_same_account() { let helpers = new FxAccountsWebChannelHelpers(); - helpers.setPreviousAccountNameHashPref("testuser@testuser.com"); - Assert.ok(helpers.shouldAllowRelink("testuser@testuser.com")); + helpers.setPreviousAccountHashPref("testuser"); + Assert.ok( + helpers.shouldAllowRelink({ + email: "testuser@testuser.com", + uid: "testuser", + }) + ); run_next_test(); }); @@ -529,7 +495,7 @@ add_test(function test_helpers_should_allow_relink_same_email() { add_test(function test_helpers_should_allow_relink_different_email() { let helpers = new FxAccountsWebChannelHelpers(); - helpers.setPreviousAccountNameHashPref("testuser@testuser.com"); + helpers.setPreviousAccountHashPref("testuser"); helpers._promptForRelink = acctName => { return acctName === "allowed_to_relink@testuser.com"; @@ -575,9 +541,10 @@ add_task(async function test_helpers_login_without_customize_sync() { }); // ensure the previous account pref is overwritten. - helpers.setPreviousAccountNameHashPref("lastuser@testuser.com"); + helpers.setPreviousAccountHashPref("lastuser"); await helpers.login({ + uid: "testuser", email: "testuser@testuser.com", verifiedCanLinkAccount: true, customizeSync: false, @@ -587,7 +554,7 @@ add_task(async function test_helpers_login_without_customize_sync() { ); }); -add_task(async function test_helpers_login_set_previous_account_name_hash() { +add_task(async function test_helpers_login_set_previous_account_hash() { let helpers = new FxAccountsWebChannelHelpers({ fxAccounts: { getSignedInUser() { @@ -598,8 +565,12 @@ add_task(async function test_helpers_login_set_previous_account_name_hash() { return new Promise(resolve => { // previously signed in user preference is updated. Assert.equal( - helpers.getPreviousAccountNameHashPref(), - CryptoUtils.sha256Base64("newuser@testuser.com") + Services.prefs.getStringPref(PREF_LAST_FXA_USER_UID), + CryptoUtils.sha256Base64("new_uid") + ); + Assert.equal( + Services.prefs.getStringPref(PREF_LAST_FXA_USER_EMAIL, ""), + "" ); resolve(); }); @@ -620,9 +591,10 @@ add_task(async function test_helpers_login_set_previous_account_name_hash() { }); // ensure the previous account pref is overwritten. - helpers.setPreviousAccountNameHashPref("lastuser@testuser.com"); + helpers.setPreviousAccountHashPref("last_uid"); await helpers.login({ + uid: "new_uid", email: "newuser@testuser.com", verifiedCanLinkAccount: true, customizeSync: false, @@ -661,6 +633,7 @@ add_task(async function test_helpers_login_another_user_signed_in() { helpers._disconnect = sinon.spy(); await helpers.login({ + uid: "testuser", email: "testuser@testuser.com", verifiedCanLinkAccount: true, customizeSync: false, @@ -705,6 +678,7 @@ add_task(async function test_helpers_login_with_customize_sync() { }); await helpers.login({ + uid: "testuser", email: "testuser@testuser.com", verifiedCanLinkAccount: true, customizeSync: true, diff --git a/services/sync/modules/SyncDisconnect.sys.mjs b/services/sync/modules/SyncDisconnect.sys.mjs @@ -10,7 +10,8 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", Log: "resource://gre/modules/Log.sys.mjs", - PREF_LAST_FXA_USER: "resource://gre/modules/FxAccountsCommon.sys.mjs", + PREF_LAST_FXA_USER_EMAIL: "resource://gre/modules/FxAccountsCommon.sys.mjs", + PREF_LAST_FXA_USER_UID: "resource://gre/modules/FxAccountsCommon.sys.mjs", Sanitizer: "resource:///modules/Sanitizer.sys.mjs", Utils: "resource://services-sync/util.sys.mjs", setTimeout: "resource://gre/modules/Timer.sys.mjs", @@ -100,7 +101,8 @@ export const SyncDisconnectInternal = { // Reset the pref which is used to show a warning when a different user // signs in - this is no longer a concern now that we've removed the // data from the profile. - Services.prefs.clearUserPref(lazy.PREF_LAST_FXA_USER); + Services.prefs.clearUserPref(lazy.PREF_LAST_FXA_USER_EMAIL); + Services.prefs.clearUserPref(lazy.PREF_LAST_FXA_USER_UID); log.info("Finished wiping sync data"); } catch (ex) { diff --git a/services/sync/tests/unit/test_disconnect_shutdown.js b/services/sync/tests/unit/test_disconnect_shutdown.js @@ -9,7 +9,7 @@ const { SyncDisconnect, SyncDisconnectInternal } = ChromeUtils.importESModule( const { AsyncShutdown } = ChromeUtils.importESModule( "resource://gre/modules/AsyncShutdown.sys.mjs" ); -const { PREF_LAST_FXA_USER } = ChromeUtils.importESModule( +const { PREF_LAST_FXA_USER_UID } = ChromeUtils.importESModule( "resource://gre/modules/FxAccountsCommon.sys.mjs" ); @@ -58,7 +58,10 @@ add_task(async function test_shutdown_blocker() { let weaveStub = sinon.stub(SyncDisconnectInternal, "getWeave"); weaveStub.returns(Weave); - Services.prefs.setStringPref(PREF_LAST_FXA_USER, "dGVzdEBleGFtcGxlLmNvbQ=="); + Services.prefs.setStringPref( + PREF_LAST_FXA_USER_UID, + "dGVzdEBleGFtcGxlLmNvbQ==" + ); let promiseDisconnected = SyncDisconnect.disconnect(true); @@ -72,7 +75,7 @@ add_task(async function test_shutdown_blocker() { await promiseDisconnected; Assert.ok( - !Services.prefs.prefHasUserValue(PREF_LAST_FXA_USER), + !Services.prefs.prefHasUserValue(PREF_LAST_FXA_USER_UID), "Should have reset different user warning pref" ); Assert.equal(