tor-browser

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

commit 2ed63cb909f43f3bd247783f75cd5d33e56a34aa
parent dbeb0cf657be6d6ce0391cf691bb07782845c5ad
Author: Cosmin Sabou <csabou@mozilla.com>
Date:   Wed, 19 Nov 2025 14:12:37 +0200

Revert "Bug 1996240: Add a method to migrate old style profiles to the new profiles system. r=profiles-reviewers,fluent-reviewers,bolsson,jhirsch,desktop-theme-reviewers,hjones" for causing failures on profileMigrate.xhtml

This reverts commit 473fe8e0a2f3a0bf702d93fc1c810d95020c1bc6.

Diffstat:
Mbrowser/components/profiles/SelectableProfileService.sys.mjs | 86++++++++++++++++++++++---------------------------------------------------------
Mbrowser/components/profiles/tests/browser/browser.toml | 2--
Dbrowser/components/profiles/tests/browser/browser_migrate.js | 157-------------------------------------------------------------------------------
Mbrowser/components/profiles/tests/browser/head.js | 24------------------------
Mtoolkit/content/aboutProfiles.js | 127++++++++++++++++---------------------------------------------------------------
Mtoolkit/locales/en-US/toolkit/about/aboutProfiles.ftl | 4----
Dtoolkit/locales/en-US/toolkit/global/profileMigrate.ftl | 25-------------------------
Dtoolkit/profile/content/profileMigrate.js | 10----------
Dtoolkit/profile/content/profileMigrate.xhtml | 65-----------------------------------------------------------------
Mtoolkit/profile/jar.mn | 2--
Mtoolkit/themes/shared/mozapps.inc.mn | 1-
Dtoolkit/themes/shared/profileMigrate.css | 32--------------------------------
12 files changed, 50 insertions(+), 485 deletions(-)

diff --git a/browser/components/profiles/SelectableProfileService.sys.mjs b/browser/components/profiles/SelectableProfileService.sys.mjs @@ -1131,26 +1131,22 @@ class SelectableProfileServiceClass extends EventEmitter { * @param {nsIFile} profileDir The root dir of the newly created profile */ async createProfileInitialFiles(profileDir) { - let timesJsonFilePath = PathUtils.join(profileDir.path, "times.json"); + let timesJsonFilePath = await IOUtils.createUniqueFile( + profileDir.path, + "times.json", + 0o700 + ); await IOUtils.writeJSON(timesJsonFilePath, { created: Date.now(), firstUse: null, }); - await IOUtils.setPermissions(timesJsonFilePath, 0o600); - - await this.updateProfilePrefs(profileDir); - } - - /** - * Create or update the prefs.js file in the given profile directory with - * all shared prefs from the database. - * - * @param {nsIFile} profileDir The root dir of the profile to update prefs for - */ - async updateProfilePrefs(profileDir) { - let prefsJsFilePath = PathUtils.join(profileDir.path, "prefs.js"); + let prefsJsFilePath = await IOUtils.createUniqueFile( + profileDir.path, + "prefs.js", + 0o600 + ); const sharedPrefs = await this.getAllDBPrefs(); @@ -1175,12 +1171,8 @@ class SelectableProfileServiceClass extends EventEmitter { const LINEBREAK = AppConstants.platform === "win" ? "\r\n" : "\n"; await IOUtils.writeUTF8( prefsJsFilePath, - Services.prefs.prefsJsPreamble + prefsJs.join(LINEBREAK) + LINEBREAK, - // If the file already exists then appending the prefs to the end serves to overwrite them. - { mode: "appendOrCreate" } + Services.prefs.prefsJsPreamble + prefsJs.join(LINEBREAK) + LINEBREAK ); - - await IOUtils.setPermissions(prefsJsFilePath, 0o600); } /** @@ -1208,35 +1200,28 @@ class SelectableProfileServiceClass extends EventEmitter { * If path is not included, new profile directories will be created. * * @param {nsIFile} existingProfilePath Optional. The path of an existing profile. - * @param {string} profileName Optional. The name for the profile. If not provided, - * a default name will be generated. * * @returns {SelectableProfile} The newly created profile object. */ - async #createProfile(existingProfilePath, profileName) { - let name; - if (profileName) { - name = profileName; - } else { - let nextProfileNumber = Math.max( - 0, - ...(await this.getAllProfiles()).map(p => p.id) - ); - let [defaultName, originalName] = - await lazy.profilesLocalization.formatMessages([ - { id: "default-profile-name", args: { number: nextProfileNumber } }, - { id: "original-profile-name" }, - ]); - - name = nextProfileNumber == 0 ? originalName.value : defaultName.value; - } + async #createProfile(existingProfilePath) { + let nextProfileNumber = Math.max( + 0, + ...(await this.getAllProfiles()).map(p => p.id) + ); + let [defaultName, originalName] = + await lazy.profilesLocalization.formatMessages([ + { id: "default-profile-name", args: { number: nextProfileNumber } }, + { id: "original-profile-name" }, + ]); let window = Services.wm.getMostRecentBrowserWindow(); let isDark = window?.matchMedia("(-moz-system-dark-theme)").matches; let randomIndex = Math.floor(Math.random() * this.#defaultAvatars.length); let profileData = { - name, + // The original toolkit profile is added first and is assigned a + // different name. + name: nextProfileNumber == 0 ? originalName.value : defaultName.value, avatar: this.#defaultAvatars[randomIndex], themeId: DEFAULT_THEME_ID, themeFg: isDark ? "rgb(255,255,255)" : "rgb(21,20,26)", @@ -1478,29 +1463,6 @@ class SelectableProfileServiceClass extends EventEmitter { } /** - * Import an existing profile directory into the selectable profiles system. - * This adds the profile to the datastore without creating new directories, - * and launches the profile in a new instance. - * - * If the user has never created a SelectableProfile before, the currently - * running toolkit profile will be added to the datastore along with the - * imported profile. - * - * @param {string} aProfileName The name for the imported profile - * @param {nsIFile} aProfileDir The existing profile directory to import - * - * @returns {SelectableProfile} The newly imported profile object. - */ - async importProfile(aProfileName, aProfileDir) { - await this.maybeSetupDataStore(); - - let profile = await this.#createProfile(aProfileDir, aProfileName); - await this.updateProfilePrefs(aProfileDir); - this.launchInstance(profile, ["about:editprofile"]); - return profile; - } - - /** * Get the complete list of profiles in the group. * * @returns {Array<SelectableProfile>} diff --git a/browser/components/profiles/tests/browser/browser.toml b/browser/components/profiles/tests/browser/browser.toml @@ -51,8 +51,6 @@ skip-if = [ ["browser_menubar_profiles.js"] head = "../unit/head.js head.js" -["browser_migrate.js"] - ["browser_moveTabToProfile.js"] ["browser_notify_changes.js"] diff --git a/browser/components/profiles/tests/browser/browser_migrate.js b/browser/components/profiles/tests/browser/browser_migrate.js @@ -1,157 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - https://creativecommons.org/publicdomain/zero/1.0/ */ - -const { sinon } = ChromeUtils.importESModule( - "resource://testing-common/Sinon.sys.mjs" -); - -add_setup(() => { - registerCleanupFunction(() => { - sinon.restore(); - }); -}); - -add_task(async () => { - Assert.ok( - !SelectableProfileService.currentProfile, - "Should not have a profile yet" - ); - - await BrowserTestUtils.withNewTab("about:profiles", async browser => { - // Override the service that about:profiles uses with our mock service. - browser.contentWindow.ProfileService = gProfileService; - - // This profile will appear to be in use because it is locked. - let newProfile = new MockProfile(gProfileService); - newProfile.name = "ProfileInUse"; - newProfile.lock(); - gProfileService.profiles.push(newProfile); - - // This profile is already in a group and so cannot be migrated. - newProfile = new MockProfile(gProfileService); - newProfile.name = "ProfileInGroup"; - newProfile.storeID = "sdkjsdhf"; - gProfileService.profiles.push(newProfile); - - // This profile can be migrated. - newProfile = new MockProfile(gProfileService); - newProfile.name = "ProfileToMigrate"; - newProfile.rootDir = newProfile.rootDir.clone(); - newProfile.rootDir.append("tomigrate"); - newProfile.rootDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700); - newProfile.localDir = newProfile.rootDir; - gProfileService.profiles.push(newProfile); - gProfileService.defaultProfile = newProfile; - - browser.contentWindow.rebuildProfileList(); - await browser.contentWindow.document.l10n.translateRoots(); - - let migrateButtons = browser.contentWindow.document.querySelectorAll( - "button[data-l10n-id='profiles-migrate-button']" - ); - Assert.equal( - migrateButtons.length, - 1, - "There should be one migrate button" - ); - Assert.equal( - migrateButtons[0].parentNode.firstChild.textContent, - "Profile: ProfileToMigrate", - "The migrate button should be for the correct profile" - ); - - let promptPromise = BrowserTestUtils.promiseAlertDialogOpen( - "cancel", - "chrome://mozapps/content/profile/profileMigrate.xhtml", - { isSubDialog: true } - ); - migrateButtons[0].click(); - await promptPromise; - - Assert.ok( - gProfileService.profiles.includes(newProfile), - "Profile not removed" - ); - - let { promise, resolve } = Promise.withResolvers(); - let execProcess = sinon.fake(resolve); - sinon.replace(SelectableProfileService, "execProcess", execProcess); - sinon.replace( - SelectableProfileService, - "sendCommandLine", - sinon.fake.throws(Cr.NS_ERROR_NOT_AVAILABLE) - ); - - promptPromise = BrowserTestUtils.promiseAlertDialogOpen( - "accept", - "chrome://mozapps/content/profile/profileMigrate.xhtml", - { isSubDialog: true } - ); - migrateButtons[0].click(); - await promptPromise; - let processArgs = await promise; - await browser.contentWindow.document.l10n.translateRoots(); - - sinon.restore(); - - Assert.ok( - !gProfileService.profiles.includes(newProfile), - "Profile was removed from the original profile service" - ); - Assert.ok( - gProfileService.profiles.includes(gProfileService.defaultProfile), - "Default profile updated" - ); - - migrateButtons = browser.contentWindow.document.querySelectorAll( - "button[data-l10n-id='profiles-migrate']" - ); - Assert.equal(migrateButtons.length, 0, "There should be no migrate button"); - - let expectedArgs = [ - "--profile", - newProfile.rootDir.path, - "-new-tab", - "about:editprofile", - ]; - - if (AppConstants.platform == "macosx") { - expectedArgs.unshift("-foreground"); - } - - Assert.deepEqual( - processArgs, - expectedArgs, - "Attempted to launch the migrated profile with the correct arguments" - ); - - let currentProfile = SelectableProfileService.currentProfile; - Assert.ok(currentProfile, "There should be a current profile now"); - - let profiles = await SelectableProfileService.getAllProfiles(); - Assert.equal(profiles.length, 2, "There should be two profiles"); - profiles = profiles.filter(p => p.id != currentProfile.id); - Assert.equal(profiles.length, 1, "The current profile was in the list"); - - Assert.equal( - profiles[0].name, - "ProfileToMigrate", - "Profile has correct name" - ); - - Assert.equal( - profiles[0].path, - newProfile.rootDir.path, - "Profile has correct path" - ); - - let prefsFile = PathUtils.join(profiles[0].path, "prefs.js"); - let prefs = (await IOUtils.readUTF8(prefsFile)).split(/\r?\n/); - Assert.ok( - prefs.includes( - `user_pref("toolkit.profiles.storeID", "${SelectableProfileService.storeID}");` - ), - "Profile contain the assigned store ID" - ); - }); -}); diff --git a/browser/components/profiles/tests/browser/head.js b/browser/components/profiles/tests/browser/head.js @@ -18,7 +18,6 @@ class MockProfile { // eslint-disable-next-line no-unused-private-class-members #service = null; #storeID = null; - #locked = false; constructor(service) { this.#service = service; @@ -29,27 +28,6 @@ class MockProfile { this.showProfileSelector = false; } - lock() { - if (this.#locked) { - throw Components.Exception("Profile already locked", Cr.NS_ERROR_FAILURE); - } - this.#locked = true; - - return { - unlock: () => { - this.#locked = false; - }, - }; - } - - remove() { - if (this.#service.defaultProfile == this) { - this.#service.defaultProfile = null; - } - - this.#service.profiles = this.#service.profiles.filter(p => p != this); - } - get storeID() { return this.#storeID; } @@ -65,8 +43,6 @@ class MockProfile { class MockProfileService { constructor() { this.currentProfile = new MockProfile(this); - this.defaultProfile = this.currentProfile; - this.profiles = [this.currentProfile]; } async asyncFlush() {} diff --git a/toolkit/content/aboutProfiles.js b/toolkit/content/aboutProfiles.js @@ -8,10 +8,6 @@ const { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ); -const { AppConstants } = ChromeUtils.importESModule( - "resource://gre/modules/AppConstants.sys.mjs" -); - XPCOMUtils.defineLazyServiceGetter( this, "ProfileService", @@ -19,13 +15,6 @@ XPCOMUtils.defineLazyServiceGetter( Ci.nsIToolkitProfileService ); -ChromeUtils.defineESModuleGetters(this, { - // Use of this must be gated on AppConstants.MOZ_SELECTABLE_PROFILES - SelectableProfileService: - // eslint-disable-next-line mozilla/no-browser-refs-in-toolkit - "resource:///modules/profiles/SelectableProfileService.sys.mjs", -}); - async function flush() { try { await ProfileService.asyncFlush(); @@ -95,7 +84,6 @@ function rebuildProfileList() { isDefault: profile == defaultProfile, isCurrentProfile, isInUse, - storeID: profile.storeID, }); } } @@ -206,22 +194,6 @@ function display(profileData) { div.appendChild(runButton); } - if ( - AppConstants.MOZ_SELECTABLE_PROFILES && - SelectableProfileService.isEnabled && - !profileData.isInUse && - !profileData.isCurrentProfile && - !profileData.storeID - ) { - let migrateButton = document.createElement("button"); - document.l10n.setAttributes(migrateButton, "profiles-migrate-button"); - migrateButton.onclick = function () { - migrateProfile(profileData.profile); - }; - - div.appendChild(migrateButton); - } - let sep = document.createElement("hr"); div.appendChild(sep); } @@ -273,31 +245,6 @@ async function renameProfile(profile) { } } -function maybeReassignDefaultProfile(profile) { - if ( - ProfileService.defaultProfile && - ProfileService.defaultProfile != profile - ) { - return; - } - - for (let p of ProfileService.profiles) { - if (profile == p) { - continue; - } - - try { - ProfileService.defaultProfile = p; - } catch (e) { - // This can happen on dev-edition if a non-default profile is in use. - // In such a case the next time that dev-edition is started it will - // find no default profile and just create a new one. - } - - break; - } -} - async function removeProfile(profile) { let deleteFiles = false; @@ -334,6 +281,32 @@ async function removeProfile(profile) { } } + // If we are deleting the default profile we must choose a different one. + let isDefault = false; + try { + isDefault = ProfileService.defaultProfile == profile; + } catch (e) {} + + if (isDefault) { + for (let p of ProfileService.profiles) { + if (profile == p) { + continue; + } + + if (isDefault) { + try { + ProfileService.defaultProfile = p; + } catch (e) { + // This can happen on dev-edition if a non-default profile is in use. + // In such a case the next time that dev-edition is started it will + // find no default profile and just create a new one. + } + } + + break; + } + } + try { profile.removeInBackground(deleteFiles); } catch (e) { @@ -346,57 +319,9 @@ async function removeProfile(profile) { return; } - // If we are deleting the default profile we must choose a different one. - maybeReassignDefaultProfile(profile); - flush(); } -async function migrateProfile(profile) { - let out = {}; - - let tabDialogBox = - window.browsingContext.topChromeWindow.gBrowser.getTabDialogBox( - window.browsingContext.embedderElement - ); - - let { closedPromise } = tabDialogBox.open( - "chrome://mozapps/content/profile/profileMigrate.xhtml", - { - features: "resizable=no", - modalType: Ci.nsIPrompt.MODAL_TYPE_CONTENT, - }, - profile.name, - out - ); - - await closedPromise; - - if (out.button != "accept") { - return; - } - - try { - profile.remove(false); - - // If we are deleting the default profile we must choose a different one. - maybeReassignDefaultProfile(profile); - - await SelectableProfileService.importProfile(profile.name, profile.rootDir); - - flush(); - } catch (e) { - console.error("Profile migration failed:", e); - - let [errorTitle, errorMsg] = await document.l10n.formatValues([ - { id: "profiles-migrate-failed-title" }, - { id: "profiles-migrate-failed-message" }, - ]); - - Services.prompt.alert(window, errorTitle, errorMsg); - } -} - async function defaultProfile(profile) { try { ProfileService.defaultProfile = profile; diff --git a/toolkit/locales/en-US/toolkit/about/aboutProfiles.ftl b/toolkit/locales/en-US/toolkit/about/aboutProfiles.ftl @@ -72,7 +72,3 @@ profiles-opendir = [windows] Open Folder *[other] Open Directory } - -profiles-migrate-button = Move to profile menu -profiles-migrate-failed-title = Migration Failed -profiles-migrate-failed-message = There was an error while attempting to migrate this profile. diff --git a/toolkit/locales/en-US/toolkit/global/profileMigrate.ftl b/toolkit/locales/en-US/toolkit/global/profileMigrate.ftl @@ -1,25 +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/. - -profile-migrate-window = - .title = Move profile - .style = min-width: 480px - -# Variables: -# $profileName (String) - Name of the profile being migrated -profile-migrate-title = Move “{ $profileName }” to the profile menu? - -profile-migrate-start = Moving this profile: - -## Bulleted list outlining what will happen if a user moves this profile. -## Appears beneath string: "Moving this profile:" (profile-migrate-start) - -profile-migrate-point1 = Will make it available in the <b>profiles</b> section of the { -brand-short-name } menu -profile-migrate-point2 = Will remove it from <b>about:profiles</b> -profile-migrate-point3 = May overwrite some settings. <a data-l10n-name="profile-migrate-link">Learn more</a> - -## - -profile-migrate-end = This move can’t be undone. -profile-migrate-accept = Move profile diff --git a/toolkit/profile/content/profileMigrate.js b/toolkit/profile/content/profileMigrate.js @@ -1,10 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - https://creativecommons.org/publicdomain/zero/1.0/ */ - -document.l10n.setArgs(document.getElementById("title"), { - profileName: window.arguments[0], -}); - -document.getElementById("dialog").addEventListener("dialogclosing", event => { - window.arguments[1].button = event.detail.button; -}); diff --git a/toolkit/profile/content/profileMigrate.xhtml b/toolkit/profile/content/profileMigrate.xhtml @@ -1,65 +0,0 @@ -<?xml version="1.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/. --> - -<?csp default-src chrome:; style-src chrome: 'unsafe-inline'; ?> - -<!DOCTYPE window> - -<window - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - prefwidth="min-width" - data-l10n-id="profile-migrate-window" - data-l10n-attrs="title,style" -> - <dialog - id="dialog" - buttonpack="end" - buttons="accept,cancel" - defaultButton="accept" - buttonidaccept="profile-migrate-accept" - > - <linkset> - <html:link rel="stylesheet" href="chrome://global/skin/global.css" /> - <html:link - rel="stylesheet" - href="chrome://mozapps/skin/profileMigrate.css" - /> - - <html:link rel="localization" href="branding/brand.ftl" /> - <html:link rel="localization" href="toolkit/global/profileMigrate.ftl" /> - </linkset> - - <script src="chrome://browser/content/utilityOverlay.js" /> - <script src="chrome://global/content/customElements.js" /> - - <div xmlns="http://www.w3.org/1999/xhtml" id="dialogBody"> - <div> - <xul:image class="question-icon" role="presentation" /> - </div> - <div> - <p id="title" data-l10n-id="profile-migrate-title"></p> - - <p id="descriptionStart" data-l10n-id="profile-migrate-start"></p> - <ul> - <li data-l10n-id="profile-migrate-point1"></li> - <li data-l10n-id="profile-migrate-point2"></li> - <li data-l10n-id="profile-migrate-point3"> - <a - is="moz-support-link" - data-l10n-name="profile-migrate-link" - noinitialfocus="true" - support-page="move-to-profile-menu" - ></a> - </li> - </ul> - <p id="warning" data-l10n-id="profile-migrate-end"></p> - </div> - </div> - - <script src="profileMigrate.js" /> - </dialog> -</window> diff --git a/toolkit/profile/jar.mn b/toolkit/profile/jar.mn @@ -5,8 +5,6 @@ toolkit.jar: content/mozapps/profile/createProfileWizard.js (content/createProfileWizard.js) content/mozapps/profile/createProfileWizard.xhtml (content/createProfileWizard.xhtml) - content/mozapps/profile/profileMigrate.js (content/profileMigrate.js) - content/mozapps/profile/profileMigrate.xhtml (content/profileMigrate.xhtml) content/mozapps/profile/profileSelection.js (content/profileSelection.js) content/mozapps/profile/profileSelection.xhtml (content/profileSelection.xhtml) #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE diff --git a/toolkit/themes/shared/mozapps.inc.mn b/toolkit/themes/shared/mozapps.inc.mn @@ -21,7 +21,6 @@ skin/classic/mozapps/aboutProfiles.css (../../shared/aboutProfiles.css) skin/classic/mozapps/aboutServiceWorkers.css (../../shared/aboutServiceWorkers.css) skin/classic/mozapps/profileDowngrade.css (../../shared/profileDowngrade.css) - skin/classic/mozapps/profileMigrate.css (../../shared/profileMigrate.css) skin/classic/mozapps/profileSelection.css (../../shared/profileSelection.css) % override chrome://mozapps/skin/extensions/category-languages.svg chrome://mozapps/skin/extensions/localeGeneric.svg diff --git a/toolkit/themes/shared/profileMigrate.css b/toolkit/themes/shared/profileMigrate.css @@ -1,32 +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/. */ - -#dialogBody { - font: menu; - display: flex; - flex-direction: row; - align-items: flex-start; -} - -.question-icon { - margin-block-start: 0; -} - -#title { - margin-block-start: 0; - font-weight: var(--heading-font-weight); -} - -ul { - padding-inline-start: var(--space-xxlarge); - margin-block-start: var(--space-small); -} - -#warning { - font-weight: var(--font-weight-bold); -} - -#descriptionStart { - margin-block-end: var(--space-small); -}