lists.torproject.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

tbb-commits

Thread Start a new thread
Threads by month
  • ----- 2026 -----
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
tbb-commits@lists.torproject.org

  • 1 participants
  • 20047 discussions
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] fixup! Firefox preference overrides.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: c02477fa by Pier Angelo Vendrame at 2025-09-08T13:44:13+00:00 fixup! Firefox preference overrides. BB 43950: Disable HEVC. HEVC support can be used for fingerprinting, as it's hardware-dependent on some systems, or depends on distribution support/installed packages for Linux. - - - - - 1 changed file: - browser/app/profile/001-base-profile.js Changes: ===================================== browser/app/profile/001-base-profile.js ===================================== @@ -483,6 +483,9 @@ pref("gfx.offscreencanvas.enabled", false); pref("dom.disable_window_move_resize", true); // Set video VP9 to 0 for everyone (bug 22548) pref("media.benchmark.vp9.threshold", 0); +// tor-browser#43950: Disable HEVC, as it will reveal lacking hardware support, +// or differences in installed codec for Linux systems. +pref("media.hevc.enabled", false); pref("privacy.resistFingerprinting.block_mozAddonManager", true); // Bug 26114 pref("dom.webmidi.enabled", false); // Bug 41398: Disable Web MIDI API // tor-browser#42043: Stop reporting device IDs (and spoof their number without View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c02477f… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c02477f… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] 3 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: 4c83f2db by Pier Angelo Vendrame at 2025-09-08T12:32:21+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - 4b7d805c by Pier Angelo Vendrame at 2025-09-08T12:32:32+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 7a6cc7a1 by Pier Angelo Vendrame at 2025-09-08T12:35:10+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 5 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -50,6 +50,8 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -61,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -106,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -596,9 +429,7 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); // Mullvad Browser-specific version of _migrateUI. this._migrateUIMB(); @@ -987,10 +818,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1827,83 +1654,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - // Use this method for any MB migration that can be run just before showing // the UI. // Anything that critically needs to be migrated earlier should not use this. ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,78 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, }; ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* 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/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,7 +136,6 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", @@ -149,6 +148,8 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b8… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b8… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] 3 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 24214f3e by Pier Angelo Vendrame at 2025-09-08T12:12:36+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - 92770da8 by Pier Angelo Vendrame at 2025-09-08T12:16:00+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 88bb3bc2 by Pier Angelo Vendrame at 2025-09-08T12:25:21+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 5 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -50,6 +50,8 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -61,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -106,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -596,9 +429,7 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) { lazy.PdfJs.checkIsDefault(this._isNewProfile); @@ -984,10 +815,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1823,83 +1650,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - async _showUpgradeDialog() { const data = await lazy.OnboardingMessageProvider.getUpgradeMessage(); const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow(); ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,78 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, }; ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* 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/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,7 +136,6 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", @@ -149,6 +148,8 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a1886d… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a1886d… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] 9 commits: fixup! BB 42019: Empty browser's clipboard on browser shutdown
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d5582e87 by Pier Angelo Vendrame at 2025-09-08T12:03:34+02:00 fixup! BB 42019: Empty browser's clipboard on browser shutdown BB 43770: Follow upstream's BrowserGlue simplifications. ClipboardPrivacy to its own file and initialize it from the manifest, rather than from BrowserGlue. - - - - - d4c6e7a4 by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00 fixup! BB 40925: Implemented the Security Level component BB 43770: Follow upstream's BrowserGlue simplifications. Initialize the security level notification from the manifest. Also, since it was the only occurrence of the file path, move it to the moz-src:// scheme. - - - - - 8eccdc93 by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00 fixup! TB 40933: Add tor-launcher functionality BB 43770: Follow upstream's BrowserGlue simplifications. Moved the call to firstWindowLoaded to the manifest. - - - - - 167c0116 by Pier Angelo Vendrame at 2025-09-08T12:03:36+02:00 fixup! TB 8324: Prevent DNS proxy bypasses caused by Drag&Drop BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - b45bb7f1 by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00 fixup! TB 43405: Show a prompt whenever we fail to apply Tor settings. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - ad267a06 by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00 fixup! TB 40458: Implement .tor.onion aliases Use proper private method and members. - - - - - a05bd724 by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00 fixup! TB 40458: Implement .tor.onion aliases BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - a857af7e by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00 fixup! BB 42027: Base Browser migration procedures. BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 51ca3bdf by Pier Angelo Vendrame at 2025-09-08T12:03:39+02:00 fixup! TB 41435: Add a Tor Browser migration function BB 43770: Follow upstream's BrowserGlue simplifications. - - - - - 12 changed files: - browser/components/BrowserComponents.manifest - browser/components/BrowserGlue.sys.mjs - browser/components/ProfileDataUpgrader.sys.mjs - browser/components/onionservices/OnionAliasStore.sys.mjs - browser/components/onionservices/moz.build - browser/components/rulesets/RulesetsParent.sys.mjs - + browser/modules/ClipboardPrivacy.sys.mjs - browser/modules/moz.build - dom/base/ContentAreaDropListener.sys.mjs - toolkit/components/places/PlacesUtils.sys.mjs - toolkit/components/tor-launcher/tor-launcher.manifest - toolkit/modules/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -51,6 +51,11 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces #endif #endif +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready +category browser-first-window-ready moz-src:///toolkit/modules/DragDropFilter.sys.mjs DragDropFilter.init +category browser-first-window-ready moz-src:///browser/modules/TorSettingsNotification.sys.mjs TorSettingsNotification.ready +category browser-first-window-ready moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.init category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes @@ -94,5 +99,6 @@ category browser-quit-application-granted moz-src:///browser/components/search/S category browser-quit-application-granted resource://gre/modules/UpdateListener.sys.mjs UpdateListener.reset #endif category browser-quit-application-granted resource:///modules/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit +category browser-quit-application-granted moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.uninit category search-service-notification moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchUIUtils.showSearchServiceNotification ===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs", ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs", AddonManager: "resource://gre/modules/AddonManager.sys.mjs", - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", BackupService: "resource:///modules/backup/BackupService.sys.mjs", BrowserSearchTelemetry: "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs", @@ -31,7 +30,6 @@ ChromeUtils.defineESModuleGetters(lazy, { DistributionManagement: "resource:///modules/distribution.sys.mjs", DownloadsViewableInternally: "resource:///modules/DownloadsViewableInternally.sys.mjs", - DragDropFilter: "resource://gre/modules/DragDropFilter.sys.mjs", ExtensionsUI: "resource:///modules/ExtensionsUI.sys.mjs", // FilePickerCrashed is used by the `listeners` object below. // eslint-disable-next-line mozilla/valid-lazy @@ -42,7 +40,6 @@ ChromeUtils.defineESModuleGetters(lazy, { LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs", MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs", NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs", - OnionAliasStore: "resource:///modules/OnionAliasStore.sys.mjs", OnboardingMessageProvider: "resource:///modules/asrouter/OnboardingMessageProvider.sys.mjs", PageDataService: "resource:///modules/pagedata/PageDataService.sys.mjs", @@ -63,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs", SearchSERPTelemetry: "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs", - SecurityLevelRestartNotification: - "resource:///modules/SecurityLevelRestartNotification.sys.mjs", SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs", SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs", ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs", @@ -75,11 +70,6 @@ ChromeUtils.defineESModuleGetters(lazy, { TelemetryReportingPolicy: "resource://gre/modules/TelemetryReportingPolicy.sys.mjs", TRRRacer: "resource:///modules/TRRPerformance.sys.mjs", - TorConnect: "resource://gre/modules/TorConnect.sys.mjs", - TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs", - TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", - TorSettingsNotification: - "resource:///modules/TorSettingsNotification.sys.mjs", WebChannel: "resource://gre/modules/WebChannel.sys.mjs", WebProtocolHandlerRegistrar: "resource:///modules/WebProtocolHandlerRegistrar.sys.mjs", @@ -113,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state"; -// Empty clipboard content from private windows on exit -// (tor-browser#42154) -const ClipboardPrivacy = { - _lastClipboardHash: null, - _globalActivation: false, - _isPrivateClipboard: false, - _hasher: null, - _shuttingDown: false, - _log: null, - - _createTransferable() { - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( - Ci.nsITransferable - ); - trans.init(null); - return trans; - }, - _computeClipboardHash() { - const flavors = ["text/x-moz-url", "text/plain"]; - if ( - !Services.clipboard.hasDataMatchingFlavors( - flavors, - Ci.nsIClipboard.kGlobalClipboard - ) - ) { - return null; - } - const trans = this._createTransferable(); - flavors.forEach(trans.addDataFlavor); - try { - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); - const clipboardContent = {}; - trans.getAnyTransferData({}, clipboardContent); - const { data } = clipboardContent.value.QueryInterface( - Ci.nsISupportsString - ); - const bytes = new TextEncoder().encode(data); - const hasher = (this._hasher ||= Cc[ - "@mozilla.org/security/hash;1" - ].createInstance(Ci.nsICryptoHash)); - hasher.init(hasher.SHA256); - hasher.update(bytes, bytes.length); - return hasher.finish(true); - } catch (e) {} - return null; - }, - - startup() { - this._log = console.createInstance({ - prefix: "ClipboardPrivacy", - }); - this._lastClipboardHash = this._computeClipboardHash(); - - // Here we track changes in active window / application, - // by filtering focus events and window closures. - const handleActivation = (win, activation) => { - if (activation) { - if (!this._globalActivation) { - // focus changed within this window, bail out. - return; - } - this._globalActivation = false; - } else if (!Services.focus.activeWindow) { - // focus is leaving this window: - // let's track whether it remains within the browser. - lazy.setTimeout(() => { - this._globalActivation = !Services.focus.activeWindow; - }, 100); - } - - const checkClipboardContent = () => { - const clipboardHash = this._computeClipboardHash(); - if (clipboardHash !== this._lastClipboardHash) { - this._isPrivateClipboard = - !activation && - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || - lazy.PrivateBrowsingUtils.isWindowPrivate(win)); - this._lastClipboardHash = clipboardHash; - this._log.debug( - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` - ); - } - }; - - if (win.closed) { - checkClipboardContent(); - } else { - // defer clipboard access on DOM events to work-around tor-browser#42306 - lazy.setTimeout(checkClipboardContent, 0); - } - }; - const focusListener = e => - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); - const initWindow = win => { - for (const e of ["focusin", "focusout"]) { - win.addEventListener(e, focusListener); - } - }; - for (const w of Services.ww.getWindowEnumerator()) { - initWindow(w); - } - Services.ww.registerNotification((win, event) => { - switch (event) { - case "domwindowopened": - initWindow(win); - break; - case "domwindowclosed": - handleActivation(win, false); - if ( - this._isPrivateClipboard && - lazy.PrivateBrowsingUtils.isWindowPrivate(win) && - (this._shuttingDown || - !Array.from(Services.ww.getWindowEnumerator()).find( - w => - lazy.PrivateBrowsingUtils.isWindowPrivate(w) && - // We need to filter out the HIDDEN WebExtensions window, - // which might be private as well but is not UI-relevant. - !w.location.href.startsWith("chrome://extensions/") - )) - ) { - // no more private windows, empty private content if needed - this.emptyPrivate(); - } - } - }); - - lazy.AsyncShutdown.quitApplicationGranted.addBlocker( - "ClipboardPrivacy: removing private data", - () => { - this._shuttingDown = true; - this.emptyPrivate(); - } - ); - }, - emptyPrivate() { - if ( - this._isPrivateClipboard && - !Services.prefs.getBoolPref( - "browser.privatebrowsing.preserveClipboard", - false - ) && - this._lastClipboardHash === this._computeClipboardHash() - ) { - // nsIClipboard.emptyClipboard() does nothing in Wayland: - // we'll set an empty string as a work-around. - const trans = this._createTransferable(); - const flavor = "text/plain"; - trans.addDataFlavor(flavor); - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - emptyString.data = ""; - trans.setTransferData(flavor, emptyString); - const { clipboard } = Services, - { kGlobalClipboard } = clipboard; - clipboard.setData(trans, null, kGlobalClipboard); - clipboard.emptyClipboard(kGlobalClipboard); - this._lastClipboardHash = null; - this._isPrivateClipboard = false; - this._log.info("Private clipboard emptied."); - } - }, -}; - ChromeUtils.defineLazyGetter( lazy, "WeaveService", @@ -603,13 +429,8 @@ BrowserGlue.prototype = { // handle any UI migration this._migrateUI(); - - // Base Browser-specific version of _migrateUI. - this._migrateUIBB(); - - // Handle any TBB-specific migration before showing the UI. Keep after - // _migrateUI to make sure this._isNewProfile has been defined. - this._migrateUITBB(); + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile); + lazy.ProfileDataUpgrader.upgradeTB(this._isNewProfile); if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) { lazy.PdfJs.checkIsDefault(this._isNewProfile); @@ -995,16 +816,6 @@ BrowserGlue.prototype = { lazy.WeaveService.init(); } - lazy.SecurityLevelRestartNotification.ready(); - - lazy.DragDropFilter.init(); - - lazy.TorProviderBuilder.firstWindowLoaded(); - - lazy.TorSettingsNotification.ready(); - - ClipboardPrivacy.startup(); - lazy.BrowserUtils.callModulesFromCategory( { categoryName: "browser-first-window-ready", @@ -1104,7 +915,6 @@ BrowserGlue.prototype = { // can perform at-shutdown tasks later in shutdown. Services.fog; }, - () => lazy.OnionAliasStore.uninit(), ]; for (let task of tasks) { @@ -1375,30 +1185,6 @@ BrowserGlue.prototype = { }, }, - { - task: () => { - if (!lazy.TorConnect.shouldShowTorConnect) { - // we will take this path when the user is using the legacy tor launcher or - // when Tor Browser didn't launch its own tor. - lazy.OnionAliasStore.init(); - } else { - // this path is taken when using about:torconnect, we wait to init - // after we are bootstrapped and connected to tor - const topic = lazy.TorConnectTopics.BootstrapComplete; - let bootstrapObserver = { - observe(aSubject, aTopic) { - if (aTopic === topic) { - lazy.OnionAliasStore.init(); - // we only need to init once, so remove ourselves as an obvserver - Services.obs.removeObserver(this, topic); - } - }, - }; - Services.obs.addObserver(bootstrapObserver, topic); - } - }, - }, - // Run TRR performance measurements for DoH. { name: "doh-rollout.trrRacer.run", @@ -1865,208 +1651,6 @@ BrowserGlue.prototype = { } }, - _migrateUIBB() { - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override - // for tor-browser#41739. - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since - // the UI is hidden. tor-browser#42777. - // Also, do not set - // dom.security.https_only_mode_send_http_background_request in - // the security level anymore (tor-browser#42149). - // Also, reset security.xfocsp.errorReporting.automatic since we - // hid its neterror checkbox. tor-browser#42653. - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. - // Version 4: 15.0a2: Drop ML components. tor-browser#44045. - const MIGRATION_VERSION = 4; - const MIGRATION_PREF = "basebrowser.migration.version"; - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUIBB: this._isNewProfile is undefined."); - } - // We do not care whether this is a new or old profile, since in version 1 - // we just quickly clear a user preference, which should not do anything to - // new profiles. - // Shall we ever raise the version number and have a watershed, we can add - // a check easily (any version > 0 will be an old profile). - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - if (currentVersion < 1) { - Services.prefs.clearUserPref( - "layout.css.prefers-color-scheme.content-override" - ); - } - if (currentVersion < 2) { - for (const prefName of [ - "privacy.globalprivacycontrol.enabled", - "privacy.donottrackheader.enabled", - // Telemetry preference for if the user changed the value. - "privacy.globalprivacycontrol.was_ever_enabled", - // The next two preferences have no corresponding UI, but are related. - "privacy.globalprivacycontrol.functionality.enabled", - "privacy.globalprivacycontrol.pbmode.enabled", - "dom.security.https_only_mode_send_http_background_request", - "security.xfocsp.errorReporting.automatic", - ]) { - Services.prefs.clearUserPref(prefName); - } - } - if (currentVersion < 3) { - Services.prefs.clearUserPref("general.smoothScroll"); - } - if (currentVersion < 4) { - for (const prefName of [ - "browser.translations.enable", - "browser.ml.enable", - "browser.ml.chat.enabled", - "browser.ml.linkPreview.enabled", - "browser.tabs.groups.smart.enabled", - "browser.tabs.groups.smart.userEnabled", - "extensions.ml.enabled", - "pdfjs.enableAltText", - "pdfjs.enableAltTextForEnglish", - "pdfjs.enableGuessAltText", - "pdfjs.enableAltTextModelDownload", - "browser.urlbar.quicksuggest.mlEnabled", - "places.semanticHistory.featureGate", - ]) { - // Preferences are locked. Do not want user values to linger in the - // user's profile and become active if these preferences become unlocked - // in the future. - Services.prefs.clearUserPref(prefName); - } - } - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); - }, - - // Use this method for any TBB migration that can be run just before showing - // the UI. - // Anything that critically needs to be migrated earlier should not use this. - async _migrateUITBB() { - // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the - // migration to packaged locales. - // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some - // torbutton preferences that are not used anymore. - // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair - // (tor-browser#42283). - // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and - // YouTube search engines (tor-browser#41835). - // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings - // since we hid the UI (tor-browser#43118). - // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is - // no longer used (tor-browser#41921). - // Drop unused TorConnect setting (tor-browser#43462). - // Version 7: Tor Browser 14.5a6: Clear home page update url preference - // (tor-browser#43567). - // Version 8: Tor Browser 15.0a2: Remove legacy search addons - // (tor-browser#43111). - const TBB_MIGRATION_VERSION = 8; - const MIGRATION_PREF = "torbrowser.migration.version"; - - // If we decide to force updating users to pass through any version - // following 12.0, we can remove this check, and check only whether - // MIGRATION_PREF has a user value, like Mozilla does. - if (this._isNewProfile) { - // Do not migrate fresh profiles - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); - return; - } else if (this._isNewProfile === undefined) { - // If this happens, check if upstream updated their function and do not - // set this member anymore! - console.error("_migrateUITBB: this._isNewProfile is undefined."); - } - - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); - const removeLangpacks = async () => { - for (const addon of await AddonManager.getAddonsByTypes(["locale"])) { - await addon.uninstall(); - } - }; - if (currentVersion < 1) { - try { - await removeLangpacks(); - } catch (err) { - console.error("Could not remove langpacks", err); - } - } - if (currentVersion < 2) { - const prefToClear = [ - // tor-browser#41845: We were forcing these value by check the value of - // automatic PBM. We decided not to change - "browser.cache.disk.enable", - "places.history.enabled", - "security.nocertdb", - "permissions.memory_only", - // Old torbutton preferences not used anymore. - "extensions.torbutton.loglevel", - "extensions.torbutton.logmethod", - "extensions.torbutton.pref_fixup_version", - "extensions.torbutton.resize_new_windows", - "extensions.torbutton.startup", - "extensions.torlauncher.prompt_for_locale", - "extensions.torlauncher.loglevel", - "extensions.torlauncher.logmethod", - "extensions.torlauncher.torrc_fixup_version", - ]; - for (const pref of prefToClear) { - if (Services.prefs.prefHasUserValue(pref)) { - Services.prefs.clearUserPref(pref); - } - } - } - const dropAddons = async list => { - for (const id of list) { - try { - const engine = await lazy.AddonManager.getAddonByID(id); - await engine?.uninstall(); - } catch {} - } - }; - if (currentVersion < 3) { - await dropAddons([ - "blockchair(a)search.mozilla.org", - "blockchair-onion(a)search.mozilla.org", - ]); - } - if (currentVersion < 4) { - await dropAddons([ - "twitter(a)search.mozilla.org", - "yahoo(a)search.mozilla.org", - "youtube(a)search.mozilla.org", - ]); - } - if (currentVersion < 5) { - for (const pref of [ - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", - ]) { - Services.prefs.clearUserPref(pref); - } - } - if (currentVersion < 6) { - Services.prefs.clearUserPref("torbrowser.settings.enabled"); - Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test"); - } - if (currentVersion < 7) { - Services.prefs.clearUserPref("torbrowser.post_update.url"); - } - if (currentVersion < 8) { - await dropAddons([ - "ddg(a)search.mozilla.org", - "ddg-onion(a)search.mozilla.org", - "google(a)search.mozilla.org", - "startpage(a)search.mozilla.org", - "startpage-onion(a)search.mozilla.org", - "wikipedia(a)search.mozilla.org", - ]); - } - - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); - }, - async _showUpgradeDialog() { const data = await lazy.OnboardingMessageProvider.getUpgradeMessage(); const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow(); ===================================== browser/components/ProfileDataUpgrader.sys.mjs ===================================== @@ -900,4 +900,200 @@ export let ProfileDataUpgrader = { // Update the migration version. Services.prefs.setIntPref("browser.migration.version", newVersion); }, + + upgradeBB(isNewProfile) { + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override + // for tor-browser#41739. + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since + // the UI is hidden. tor-browser#42777. + // Also, do not set + // dom.security.https_only_mode_send_http_background_request in + // the security level anymore (tor-browser#42149). + // Also, reset security.xfocsp.errorReporting.automatic since we + // hid its neterror checkbox. tor-browser#42653. + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070. + // Version 4: 15.0a2: Drop ML components. tor-browser#44045. + const MIGRATION_VERSION = 4; + const MIGRATION_PREF = "basebrowser.migration.version"; + + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeBB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + if (currentVersion < 1) { + Services.prefs.clearUserPref( + "layout.css.prefers-color-scheme.content-override" + ); + } + if (currentVersion < 2) { + for (const prefName of [ + "privacy.globalprivacycontrol.enabled", + "privacy.donottrackheader.enabled", + // Telemetry preference for if the user changed the value. + "privacy.globalprivacycontrol.was_ever_enabled", + // The next two preferences have no corresponding UI, but are related. + "privacy.globalprivacycontrol.functionality.enabled", + "privacy.globalprivacycontrol.pbmode.enabled", + "dom.security.https_only_mode_send_http_background_request", + "security.xfocsp.errorReporting.automatic", + ]) { + Services.prefs.clearUserPref(prefName); + } + } + if (currentVersion < 3) { + Services.prefs.clearUserPref("general.smoothScroll"); + } + if (currentVersion < 4) { + for (const prefName of [ + "browser.translations.enable", + "browser.ml.enable", + "browser.ml.chat.enabled", + "browser.ml.linkPreview.enabled", + "browser.tabs.groups.smart.enabled", + "browser.tabs.groups.smart.userEnabled", + "extensions.ml.enabled", + "pdfjs.enableAltText", + "pdfjs.enableAltTextForEnglish", + "pdfjs.enableGuessAltText", + "pdfjs.enableAltTextModelDownload", + "browser.urlbar.quicksuggest.mlEnabled", + "places.semanticHistory.featureGate", + ]) { + // Preferences are locked. Do not want user values to linger in the + // user's profile and become active if these preferences become unlocked + // in the future. + Services.prefs.clearUserPref(prefName); + } + } + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION); + }, + + async upgradeTB(isNewProfile) { + // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the + // migration to packaged locales. + // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some + // torbutton preferences that are not used anymore. + // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair + // (tor-browser#42283). + // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and + // YouTube search engines (tor-browser#41835). + // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings + // since we hid the UI (tor-browser#43118). + // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is + // no longer used (tor-browser#41921). + // Drop unused TorConnect setting (tor-browser#43462). + // Version 7: Tor Browser 14.5a6: Clear home page update url preference + // (tor-browser#43567). + // Version 8: Tor Browser 15.0a2: Remove legacy search addons + // (tor-browser#43111). + const TBB_MIGRATION_VERSION = 8; + const MIGRATION_PREF = "torbrowser.migration.version"; + + // If we decide to force updating users to pass through any version + // following 12.0, we can remove this check, and check only whether + // MIGRATION_PREF has a user value, like Mozilla does. + if (isNewProfile) { + // Do not migrate fresh profiles + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); + return; + } else if (isNewProfile === undefined) { + // If this happens, check if upstream updated their function and do not + // set this member anymore! + console.error("upgradeTB: isNewProfile is undefined."); + } + + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0); + const removeLangpacks = async () => { + for (const addon of await AddonManager.getAddonsByTypes(["locale"])) { + await addon.uninstall(); + } + }; + if (currentVersion < 1) { + try { + await removeLangpacks(); + } catch (err) { + console.error("Could not remove langpacks", err); + } + } + if (currentVersion < 2) { + const prefToClear = [ + // tor-browser#41845: We were forcing these value by check the value of + // automatic PBM. We decided not to change + "browser.cache.disk.enable", + "places.history.enabled", + "security.nocertdb", + "permissions.memory_only", + // Old torbutton preferences not used anymore. + "extensions.torbutton.loglevel", + "extensions.torbutton.logmethod", + "extensions.torbutton.pref_fixup_version", + "extensions.torbutton.resize_new_windows", + "extensions.torbutton.startup", + "extensions.torlauncher.prompt_for_locale", + "extensions.torlauncher.loglevel", + "extensions.torlauncher.logmethod", + "extensions.torlauncher.torrc_fixup_version", + ]; + for (const pref of prefToClear) { + if (Services.prefs.prefHasUserValue(pref)) { + Services.prefs.clearUserPref(pref); + } + } + } + const dropAddons = async list => { + for (const id of list) { + try { + const engine = await lazy.AddonManager.getAddonByID(id); + await engine?.uninstall(); + } catch {} + } + }; + if (currentVersion < 3) { + await dropAddons([ + "blockchair(a)search.mozilla.org", + "blockchair-onion(a)search.mozilla.org", + ]); + } + if (currentVersion < 4) { + await dropAddons([ + "twitter(a)search.mozilla.org", + "yahoo(a)search.mozilla.org", + "youtube(a)search.mozilla.org", + ]); + } + if (currentVersion < 5) { + for (const pref of [ + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features", + ]) { + Services.prefs.clearUserPref(pref); + } + } + if (currentVersion < 6) { + Services.prefs.clearUserPref("torbrowser.settings.enabled"); + Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test"); + } + if (currentVersion < 7) { + Services.prefs.clearUserPref("torbrowser.post_update.url"); + } + if (currentVersion < 8) { + await dropAddons([ + "ddg(a)search.mozilla.org", + "ddg-onion(a)search.mozilla.org", + "google(a)search.mozilla.org", + "startpage(a)search.mozilla.org", + "startpage-onion(a)search.mozilla.org", + "wikipedia(a)search.mozilla.org", + ]); + } + + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); + }, }; ===================================== browser/components/onionservices/OnionAliasStore.sys.mjs ===================================== @@ -1,4 +1,6 @@ -// Copyright (c) 2022, The Tor Project, Inc. +/* 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/. */ import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs"; @@ -6,7 +8,10 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { JSONFile: "resource://gre/modules/JSONFile.sys.mjs", - TorRequestWatch: "resource:///modules/TorRequestWatch.sys.mjs", + TorConnect: "resource://gre/modules/TorConnect.sys.mjs", + TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs", + TorRequestWatch: + "moz-src:///browser/components/onionservices/TorRequestWatch.sys.mjs", }); /* OnionAliasStore observer topics */ @@ -84,12 +89,14 @@ class Channel { }; } + #enabled; + constructor(name, pathPrefix, jwk, scope, enabled) { this.name = name; this.pathPrefix = pathPrefix; this.jwk = jwk; this.scope = scope; - this._enabled = enabled; + this.#enabled = enabled; this.mappings = []; this.currentTimestamp = 0; @@ -158,10 +165,10 @@ class Channel { log.debug( `Downloaded and verified rules for ${this.name}, now uncompressing` ); - this._makeMappings(JSON.parse(await gunzip(rulesGz))); + this.#makeMappings(JSON.parse(await gunzip(rulesGz))); } - _makeMappings(rules) { + #makeMappings(rules) { const toTest = /^https?:\/\/[a-zA-Z0-9\.]{56}\.onion$/; const mappings = []; rules.rulesets.forEach(rule => { @@ -210,7 +217,7 @@ class Channel { async updateMappings(force) { force = force === undefined ? false : !!force; - if (!this._enabled && !force) { + if (!this.#enabled && !force) { return; } await this.updateLatestTimestamp(); @@ -224,10 +231,10 @@ class Channel { } get enabled() { - return this._enabled; + return this.#enabled; } set enabled(enabled) { - this._enabled = enabled; + this.#enabled = enabled; if (!enabled) { this.mappings = []; this.currentTimestamp = 0; @@ -243,7 +250,7 @@ class Channel { pathPrefix: this.pathPrefix, jwk: this.jwk, scope, - enabled: this._enabled, + enabled: this.#enabled, mappings: this.mappings, currentTimestamp: this.currentTimestamp, }; @@ -277,37 +284,40 @@ class _OnionAliasStore { return 86400 * 1000; // 1 day, like HTTPS-Everywhere } - constructor() { - this._channels = new Map(); - this._rulesetTimeout = null; - this._lastCheck = 0; - this._storage = null; - } + #channels = new Map(); + #rulesetTimeout = null; + #lastCheck = 0; + #storage = null; async init() { lazy.TorRequestWatch.start(); - await this._loadSettings(); - if (this.enabled) { - await this._startUpdates(); + await this.#loadSettings(); + if (this.enabled && !lazy.TorConnect.shouldShowTorConnect) { + await this.#startUpdates(); + } else { + Services.obs.addObserver(this, lazy.TorConnectTopics.BootstrapComplete); } Services.prefs.addObserver(kPrefOnionAliasEnabled, this); } uninit() { - this._clear(); - if (this._rulesetTimeout) { - clearTimeout(this._rulesetTimeout); + this.#clear(); + if (this.#rulesetTimeout) { + clearTimeout(this.#rulesetTimeout); } - this._rulesetTimeout = null; + this.#rulesetTimeout = null; + + Services.obs.removeObserver(this, lazy.TorConnectTopics.BootstrapComplete); Services.prefs.removeObserver(kPrefOnionAliasEnabled, this); + lazy.TorRequestWatch.stop(); } async getChannels() { - if (this._storage === null) { - await this._loadSettings(); + if (this.#storage === null) { + await this.#loadSettings(); } - return Array.from(this._channels.values(), ch => ch.toJSON()); + return Array.from(this.#channels.values(), ch => ch.toJSON()); } async setChannel(chanData) { @@ -328,20 +338,20 @@ class _OnionAliasStore { ); // Call makeKey to make it throw if the key is invalid await ch.makeKey(); - this._channels.set(name, ch); - this._applyMappings(); - this._saveSettings(); - setTimeout(this._notifyChanges.bind(this), 1); + this.#channels.set(name, ch); + this.#applyMappings(); + this.#saveSettings(); + setTimeout(this.#notifyChanges.bind(this), 1); return ch; } enableChannel(name, enabled) { - const channel = this._channels.get(name); + const channel = this.#channels.get(name); if (channel !== null) { channel.enabled = enabled; - this._applyMappings(); - this._saveSettings(); - this._notifyChanges(); + this.#applyMappings(); + this.#saveSettings(); + this.#notifyChanges(); if (this.enabled && enabled && !channel.currentTimestamp) { this.updateChannel(name); } @@ -352,46 +362,46 @@ class _OnionAliasStore { if (!this.enabled) { throw Error("Onion Aliases are disabled"); } - const channel = this._channels.get(name); + const channel = this.#channels.get(name); if (channel === null) { throw Error("Channel not found"); } await channel.updateMappings(true); - this._saveSettings(); - this._applyMappings(); - setTimeout(this._notifyChanges.bind(this), 1); + this.#saveSettings(); + this.#applyMappings(); + setTimeout(this.#notifyChanges.bind(this), 1); return channel; } deleteChannel(name) { - if (this._channels.delete(name)) { - this._saveSettings(); - this._applyMappings(); - this._notifyChanges(); + if (this.#channels.delete(name)) { + this.#saveSettings(); + this.#applyMappings(); + this.#notifyChanges(); } } - async _loadSettings() { - if (this._storage !== null) { + async #loadSettings() { + if (this.#storage !== null) { return; } - this._channels = new Map(); - this._storage = new lazy.JSONFile({ + this.#channels = new Map(); + this.#storage = new lazy.JSONFile({ path: PathUtils.join( Services.dirsvc.get("ProfD", Ci.nsIFile).path, "onion-aliases.json" ), - dataPostProcessor: this._settingsProcessor.bind(this), + dataPostProcessor: this.#settingsProcessor.bind(this), }); - await this._storage.load(); - log.debug("Loaded settings", this._storage.data, this._storage.path); - this._applyMappings(); - this._notifyChanges(); + await this.#storage.load(); + log.debug("Loaded settings", this.#storage.data, this.#storage.path); + this.#applyMappings(); + this.#notifyChanges(); } - _settingsProcessor(data) { + #settingsProcessor(data) { if ("lastCheck" in data) { - this._lastCheck = data.lastCheck; + this.#lastCheck = data.lastCheck; } else { data.lastCheck = 0; } @@ -410,56 +420,56 @@ class _OnionAliasStore { } return true; }); - this._channels = channels; + this.#channels = channels; return data; } - _saveSettings() { - if (this._storage === null) { + #saveSettings() { + if (this.#storage === null) { throw Error("Settings have not been loaded"); } - this._storage.data.lastCheck = this._lastCheck; - this._storage.data.channels = Array.from(this._channels.values(), ch => + this.#storage.data.lastCheck = this.#lastCheck; + this.#storage.data.channels = Array.from(this.#channels.values(), ch => ch.toJSON() ); - this._storage.saveSoon(); + this.#storage.saveSoon(); } - _addMapping(shortOnionHost, longOnionHost) { + #addMapping(shortOnionHost, longOnionHost) { const service = Cc["@torproject.org/onion-alias-service;1"].getService( Ci.IOnionAliasService ); service.addOnionAlias(shortOnionHost, longOnionHost); } - _clear() { + #clear() { const service = Cc["@torproject.org/onion-alias-service;1"].getService( Ci.IOnionAliasService ); service.clearOnionAliases(); } - _applyMappings() { - this._clear(); - for (const ch of this._channels.values()) { + #applyMappings() { + this.#clear(); + for (const ch of this.#channels.values()) { if (!ch.enabled) { continue; } for (const [short, long] of ch.mappings) { - this._addMapping(short, long); + this.#addMapping(short, long); } } } - async _periodicRulesetCheck() { + async #periodicRulesetCheck() { if (!this.enabled) { log.debug("Onion Aliases are disabled, not updating rulesets."); return; } log.debug("Begin scheduled ruleset update"); - this._lastCheck = Date.now(); + this.#lastCheck = Date.now(); let anyUpdated = false; - for (const ch of this._channels.values()) { + for (const ch of this.#channels.values()) { if (!ch.enabled) { log.debug(`Not updating ${ch.name} because not enabled`); continue; @@ -473,22 +483,22 @@ class _OnionAliasStore { } } if (anyUpdated) { - this._saveSettings(); - this._applyMappings(); - this._notifyChanges(); + this.#saveSettings(); + this.#applyMappings(); + this.#notifyChanges(); } else { log.debug("No channel has been updated, avoid saving"); } - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL); + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL); } - async _startUpdates() { - // This is a "private" function, so we expect the callers to verify wheter + async #startUpdates() { + // This is a private function, so we expect the callers to verify whether // onion aliases are enabled. // Callees will also do, so we avoid an additional check here. - const dt = Date.now() - this._lastCheck; + const dt = Date.now() - this.#lastCheck; let force = false; - for (const ch of this._channels.values()) { + for (const ch of this.#channels.values()) { if (ch.enabled && !ch.currentTimestamp) { // Edited while being offline or some other error happened force = true; @@ -499,34 +509,34 @@ class _OnionAliasStore { log.debug( `Mappings are stale (${dt}), or force check requested (${force}), checking them immediately` ); - await this._periodicRulesetCheck(); + await this.#periodicRulesetCheck(); } else { - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt); + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt); } } - _scheduleCheck(dt) { - if (this._rulesetTimeout) { + #scheduleCheck(dt) { + if (this.#rulesetTimeout) { log.warn("The previous update timeout was not null"); - clearTimeout(this._rulesetTimeout); + clearTimeout(this.#rulesetTimeout); } if (!this.enabled) { log.warn( "Ignoring the scheduling of a new check because the Onion Alias feature is currently disabled." ); - this._rulesetTimeout = null; + this.#rulesetTimeout = null; return; } log.debug(`Scheduling ruleset update in ${dt}`); - this._rulesetTimeout = setTimeout(() => { - this._rulesetTimeout = null; - this._periodicRulesetCheck(); + this.#rulesetTimeout = setTimeout(() => { + this.#rulesetTimeout = null; + this.#periodicRulesetCheck(); }, dt); } - _notifyChanges() { + #notifyChanges() { Services.obs.notifyObservers( - Array.from(this._channels.values(), ch => ch.toJSON()), + Array.from(this.#channels.values(), ch => ch.toJSON()), OnionAliasStoreTopics.ChannelsChanged ); } @@ -538,11 +548,16 @@ class _OnionAliasStore { observe(aSubject, aTopic) { if (aTopic === "nsPref:changed") { if (this.enabled) { - this._startUpdates(); - } else if (this._rulesetTimeout) { - clearTimeout(this._rulesetTimeout); - this._rulesetTimeout = null; + this.#startUpdates(); + } else if (this.#rulesetTimeout) { + clearTimeout(this.#rulesetTimeout); + this.#rulesetTimeout = null; } + } else if ( + aTopic === lazy.TorConnectTopics.BootstrapComplete && + this.enabled + ) { + this.#startUpdates(); } } } ===================================== browser/components/onionservices/moz.build ===================================== @@ -1,8 +1,11 @@ JAR_MANIFESTS += ["jar.mn"] EXTRA_JS_MODULES += [ - "OnionAliasStore.sys.mjs", "OnionLocationChild.sys.mjs", "OnionLocationParent.sys.mjs", +] + +MOZ_SRC_FILES += [ + "OnionAliasStore.sys.mjs", "TorRequestWatch.sys.mjs", ] ===================================== browser/components/rulesets/RulesetsParent.sys.mjs ===================================== @@ -1,9 +1,11 @@ -// Copyright (c) 2022, The Tor Project, Inc. +/* 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/. */ import { OnionAliasStore, OnionAliasStoreTopics, -} from "resource:///modules/OnionAliasStore.sys.mjs"; +} from "moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs"; const kShowWarningPref = "torbrowser.rulesets.show_warning"; @@ -56,9 +58,10 @@ export class RulesetsParent extends JSWindowActorParent { return { showWarning: Services.prefs.getBoolPref(kShowWarningPref, true), }; - case "rulesets:set-channel": + case "rulesets:set-channel": { const ch = await OnionAliasStore.setChannel(message.data); return ch; + } case "rulesets:update-channel": // We need to catch any error in this way, because in case of an // exception, RPMSendQuery does not return on the other side ===================================== browser/modules/ClipboardPrivacy.sys.mjs ===================================== @@ -0,0 +1,178 @@ +/* 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/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", +}); + +/** + * Empty clipboard content from private windows on exit. + * + * See tor-browser#42154. + */ +export const ClipboardPrivacy = { + _lastClipboardHash: null, + _globalActivation: false, + _isPrivateClipboard: false, + _hasher: null, + _shuttingDown: false, + _log: null, + + _createTransferable() { + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance( + Ci.nsITransferable + ); + trans.init(null); + return trans; + }, + _computeClipboardHash() { + const flavors = ["text/x-moz-url", "text/plain"]; + if ( + !Services.clipboard.hasDataMatchingFlavors( + flavors, + Ci.nsIClipboard.kGlobalClipboard + ) + ) { + return null; + } + const trans = this._createTransferable(); + flavors.forEach(trans.addDataFlavor); + try { + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard); + const clipboardContent = {}; + trans.getAnyTransferData({}, clipboardContent); + const { data } = clipboardContent.value.QueryInterface( + Ci.nsISupportsString + ); + const bytes = new TextEncoder().encode(data); + const hasher = (this._hasher ||= Cc[ + "@mozilla.org/security/hash;1" + ].createInstance(Ci.nsICryptoHash)); + hasher.init(hasher.SHA256); + hasher.update(bytes, bytes.length); + return hasher.finish(true); + } catch (e) {} + return null; + }, + + init() { + this._log = console.createInstance({ + prefix: "ClipboardPrivacy", + }); + this._lastClipboardHash = this._computeClipboardHash(); + + // Here we track changes in active window / application, + // by filtering focus events and window closures. + const handleActivation = (win, activation) => { + if (activation) { + if (!this._globalActivation) { + // focus changed within this window, bail out. + return; + } + this._globalActivation = false; + } else if (!Services.focus.activeWindow) { + // focus is leaving this window: + // let's track whether it remains within the browser. + lazy.setTimeout(() => { + this._globalActivation = !Services.focus.activeWindow; + }, 100); + } + + const checkClipboardContent = () => { + const clipboardHash = this._computeClipboardHash(); + if (clipboardHash !== this._lastClipboardHash) { + this._isPrivateClipboard = + !activation && + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing || + lazy.PrivateBrowsingUtils.isWindowPrivate(win)); + this._lastClipboardHash = clipboardHash; + this._log.debug( + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.` + ); + } + }; + + if (win.closed) { + checkClipboardContent(); + } else { + // defer clipboard access on DOM events to work-around tor-browser#42306 + lazy.setTimeout(checkClipboardContent, 0); + } + }; + const focusListener = e => + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin"); + const initWindow = win => { + for (const e of ["focusin", "focusout"]) { + win.addEventListener(e, focusListener); + } + }; + for (const w of Services.ww.getWindowEnumerator()) { + initWindow(w); + } + Services.ww.registerNotification((win, event) => { + switch (event) { + case "domwindowopened": + initWindow(win); + break; + case "domwindowclosed": + handleActivation(win, false); + if ( + this._isPrivateClipboard && + lazy.PrivateBrowsingUtils.isWindowPrivate(win) && + (this._shuttingDown || + !Array.from(Services.ww.getWindowEnumerator()).find( + w => + lazy.PrivateBrowsingUtils.isWindowPrivate(w) && + // We need to filter out the HIDDEN WebExtensions window, + // which might be private as well but is not UI-relevant. + !w.location.href.startsWith("chrome://extensions/") + )) + ) { + // no more private windows, empty private content if needed + this.emptyPrivate(); + } + } + }); + + lazy.AsyncShutdown.quitApplicationGranted.addBlocker( + "ClipboardPrivacy: removing private data", + () => { + this._shuttingDown = true; + this.emptyPrivate(); + } + ); + }, + emptyPrivate() { + if ( + this._isPrivateClipboard && + !Services.prefs.getBoolPref( + "browser.privatebrowsing.preserveClipboard", + false + ) && + this._lastClipboardHash === this._computeClipboardHash() + ) { + // nsIClipboard.emptyClipboard() does nothing in Wayland: + // we'll set an empty string as a work-around. + const trans = this._createTransferable(); + const flavor = "text/plain"; + trans.addDataFlavor(flavor); + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + emptyString.data = ""; + trans.setTransferData(flavor, emptyString); + const { clipboard } = Services, + { kGlobalClipboard } = clipboard; + clipboard.setData(trans, null, kGlobalClipboard); + clipboard.emptyClipboard(kGlobalClipboard); + this._lastClipboardHash = null; + this._isPrivateClipboard = false; + this._log.info("Private clipboard emptied."); + } + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -136,12 +136,10 @@ EXTRA_JS_MODULES += [ "PopupBlockerObserver.sys.mjs", "ProcessHangMonitor.sys.mjs", "Sanitizer.sys.mjs", - "SecurityLevelRestartNotification.sys.mjs", "SelectionChangedMenulist.sys.mjs", "SharingUtils.sys.mjs", "SiteDataManager.sys.mjs", "SitePermissions.sys.mjs", - "TorSettingsNotification.sys.mjs", "TorUIUtils.sys.mjs", "TransientPrefs.sys.mjs", "URILoadingHelper.sys.mjs", @@ -151,6 +149,9 @@ EXTRA_JS_MODULES += [ MOZ_SRC_FILES += [ "ContextId.sys.mjs", + "ClipboardPrivacy.sys.mjs", + "SecurityLevelRestartNotification.sys.mjs", + "TorSettingsNotification.sys.mjs", ] if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": ===================================== dom/base/ContentAreaDropListener.sys.mjs ===================================== @@ -5,7 +5,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs", + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs", }); // This component is used for handling dragover and drop of urls. ===================================== toolkit/components/places/PlacesUtils.sys.mjs ===================================== @@ -12,7 +12,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { Bookmarks: "resource://gre/modules/Bookmarks.sys.mjs", History: "resource://gre/modules/History.sys.mjs", - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs", + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs", PlacesSyncUtils: "resource://gre/modules/PlacesSyncUtils.sys.mjs", Sqlite: "resource://gre/modules/Sqlite.sys.mjs", }); ===================================== toolkit/components/tor-launcher/tor-launcher.manifest ===================================== @@ -1 +1,2 @@ category profile-after-change TorStartupService @torproject.org/tor-startup-service;1 +category browser-first-window-ready resource://gre/modules/TorProviderBuilder.sys.mjs TorProviderBuilder.firstWindowLoaded ===================================== toolkit/modules/moz.build ===================================== @@ -164,7 +164,6 @@ EXTRA_JS_MODULES += [ "DateTimePickerPanel.sys.mjs", "DeferredTask.sys.mjs", "DomainFrontedRequests.sys.mjs", - "DragDropFilter.sys.mjs", "E10SUtils.sys.mjs", "EventEmitter.sys.mjs", "FileUtils.sys.mjs", @@ -220,6 +219,10 @@ EXTRA_JS_MODULES += [ "WebChannel.sys.mjs", ] +MOZ_SRC_FILES += [ + "DragDropFilter.sys.mjs", +] + if CONFIG["MOZ_ASAN_REPORTER"]: EXTRA_JS_MODULES += [ "AsanReporter.sys.mjs", View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d28d9f… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d28d9f… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] BB 43525: Skip Remote Settings for search engine customization.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: a1886d8c by Pier Angelo Vendrame at 2025-09-08T11:57:50+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - 9 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - + toolkit/components/search/content/base-browser-search-engine-icons.json - + toolkit/components/search/content/base-browser-search-engines.json - + toolkit/components/search/content/duckduckgo.ico - + toolkit/components/search/content/startpage-16.png - + toolkit/components/search/content/startpage-32.png - + toolkit/components/search/jar.mn - toolkit/components/search/moz.build Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,6 +116,10 @@ class IconHandler { await this.#buildIconMap(); } + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) @@ -132,29 +136,7 @@ class IconHandler { * source object or null of there is no icon with the supplied width. */ async createIconURL(iconRecord) { - let iconData; - try { - iconData = await this.#iconCollection.attachments.get(iconRecord); - } catch (ex) { - console.error(ex); - } - if (!iconData) { - console.warn("Unable to find the attachment for", iconRecord.id); - // Queue an update in case we haven't downloaded it yet. - this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); - this.#maybeQueueIdle(); - return null; - } - - if (iconData.record.last_modified != iconRecord.last_modified) { - // The icon we have stored is out of date, queue an update so that we'll - // download the new icon. - this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); - this.#maybeQueueIdle(); - } - return URL.createObjectURL( - new Blob([iconData.buffer], { type: iconRecord.attachment.mimetype }) - ); + return iconRecord.url; } QueryInterface = ChromeUtils.generateQI(["nsIObserver"]); @@ -238,27 +220,23 @@ class IconHandler { * Obtains the icon list from the remote settings collection. */ async #buildIconMap() { - let iconList = []; try { - iconList = await this.#iconCollection.get(); + this.#iconMap = new Map( + Object.entries( + await ( + await fetch( + "chrome://global/content/search/base-browser-search-engine-icons.json" + ) + ).json() + ) + ); } catch (ex) { console.error(ex); + this.#iconMap = null; } - if (!iconList.length) { + if (!this.#iconMap) { console.error("Failed to obtain search engine icon list records"); } - - this.#iconMap = new Map(); - for (let record of iconList) { - let keys = new Set(record.engineIdentifiers.map(this.getKey)); - for (let key of keys) { - if (this.#iconMap.has(key)) { - this.#iconMap.get(key).push(record); - } else { - this.#iconMap.set(key, [record]); - } - } - } } /** ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -2,6 +2,8 @@ * 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 { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } - this._getConfigurationPromise = Promise.all([ - this._getConfiguration(), - this._getConfigurationOverrides(), - ]); - let remoteSettingsData = await this._getConfigurationPromise; - this._configuration = remoteSettingsData[0]; - this._configurationOverrides = remoteSettingsData[1]; - delete this._getConfigurationPromise; - - if (!this._configuration?.length) { - throw Components.Exception( - "Failed to get engine data from Remote Settings", - Cr.NS_ERROR_UNEXPECTED - ); - } - - if (!this._listenerAdded) { - this._remoteConfig.on("sync", this._onConfigurationUpdated); - this._remoteConfigOverrides.on( - "sync", - this._onConfigurationOverridesUpdated - ); - this._listenerAdded = true; - } + let { promise, resolve } = Promise.withResolvers(); + this._getConfigurationPromise = promise; + this._configuration = await ( + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) + ).json(); + this._configurationOverrides = []; + resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { ===================================== toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -0,0 +1,15 @@ +{ + "ddg": [ + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } + ], + "startpage": [ + { + "url": "chrome://global/content/search/startpage-16.png", + "imageSize": 16 + }, + { + "url": "chrome://global/content/search/startpage-32.png", + "imageSize": 32 + } + ] +} ===================================== toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -0,0 +1,43 @@ +[ + { + "base": { + "aliases": ["duckduckgo", "ddg"], + "classification": "general", + "name": "DuckDuckGo", + "urls": { + "search": { + "base": "https://duckduckgo.com/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", + "identifier": "ddg", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["startpage", "sp"], + "classification": "general", + "name": "Startpage", + "urls": { + "search": { + "base": "https://www.startpage.com/sp/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", + "identifier": "startpage", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "recordType": "defaultEngines", + "globalDefault": "ddg", + "globalDefaultPrivate": "ddg" + } +] ===================================== toolkit/components/search/content/duckduckgo.ico ===================================== Binary files /dev/null and b/toolkit/components/search/content/duckduckgo.ico differ ===================================== toolkit/components/search/content/startpage-16.png ===================================== Binary files /dev/null and b/toolkit/components/search/content/startpage-16.png differ ===================================== toolkit/components/search/content/startpage-32.png ===================================== Binary files /dev/null and b/toolkit/components/search/content/startpage-32.png differ ===================================== toolkit/components/search/jar.mn ===================================== @@ -0,0 +1,6 @@ +# 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/. + +toolkit.jar: + content/global/search/ (content/*) ===================================== toolkit/components/search/moz.build ===================================== @@ -46,5 +46,7 @@ TESTING_JS_MODULES += [ "tests/SearchTestUtils.sys.mjs", ] +JAR_MANIFESTS += ["jar.mn"] + with Files("**"): BUG_COMPONENT = ("Firefox", "Search") View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/a1886d8… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/a1886d8… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] 4 commits: fixup! MB 213: Customize the search engines list
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: fd210716 by Pier Angelo Vendrame at 2025-09-08T11:52:36+02:00 fixup! MB 213: Customize the search engines list BB 43525: Skip Remote Settings for search engine customization. Drop some changes that we are not going to keep with the shared approach. - - - - - 0c345e48 by Pier Angelo Vendrame at 2025-09-08T11:53:16+02:00 dropme! MB 213: Customize the search engines list BB 43525: Skip Remote Settings for search engine customization. Prepare the tree for the new approach. - - - - - e95419fa by Pier Angelo Vendrame at 2025-09-08T11:53:17+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - b80c84c1 by Pier Angelo Vendrame at 2025-09-08T11:53:17+02:00 amend! MB 213: Customize the search engines list MB 213: Customize the search engines list. - - - - - 6 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - toolkit/components/search/SearchService.sys.mjs - toolkit/components/search/content/mullvadBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json - + toolkit/components/search/content/base-browser-search-engines.json - − toolkit/components/search/content/mullvadBrowserSearchEngines.json Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,7 +116,14 @@ class IconHandler { await this.#buildIconMap(); } - return this.#iconMap.get(engineIdentifier); + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; + return iconList.filter(r => + this.#identifierMatches(engineIdentifier, r.engineIdentifiers) + ); } /** @@ -218,7 +225,7 @@ class IconHandler { Object.entries( await ( await fetch( - "chrome://global/content/search/mullvadBrowserSearchEngineIcons.json" + "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -2,6 +2,8 @@ * 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 { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } - this._getConfigurationPromise = Promise.all([ - this._getConfiguration(), - this._getConfigurationOverrides(), - ]); - let remoteSettingsData = await this._getConfigurationPromise; - this._configuration = remoteSettingsData[0]; - this._configurationOverrides = remoteSettingsData[1]; - delete this._getConfigurationPromise; - - if (!this._configuration?.length) { - throw Components.Exception( - "Failed to get engine data from Remote Settings", - Cr.NS_ERROR_UNEXPECTED - ); - } - - if (!this._listenerAdded) { - this._remoteConfig.on("sync", this._onConfigurationUpdated); - this._remoteConfigOverrides.on( - "sync", - this._onConfigurationOverridesUpdated - ); - this._listenerAdded = true; - } + let { promise, resolve } = Promise.withResolvers(); + this._getConfigurationPromise = promise; + this._configuration = await ( + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) + ).json(); + this._configurationOverrides = []; + resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { + // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do + // not want them to interfere in any way. + if (AppConstants.BASE_BROWSER_VERSION) { + return; + } + this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { ===================================== toolkit/components/search/SearchService.sys.mjs ===================================== @@ -25,7 +25,6 @@ ChromeUtils.defineESModuleGetters(lazy, { Region: "resource://gre/modules/Region.sys.mjs", RemoteSettings: "resource://services-settings/remote-settings.sys.mjs", SearchEngine: "moz-src:///toolkit/components/search/SearchEngine.sys.mjs", - // eslint-disable-next-line mozilla/valid-lazy SearchEngineSelector: "moz-src:///toolkit/components/search/SearchEngineSelector.sys.mjs", SearchSettings: "moz-src:///toolkit/components/search/SearchSettings.sys.mjs", @@ -579,7 +578,11 @@ export class SearchService { // Test-only function to reset just the engine selector so that it can // load a different configuration. - resetEngineSelector() {} + resetEngineSelector() { + this.#engineSelector = new lazy.SearchEngineSelector( + this.#handleConfigurationUpdated.bind(this) + ); + } resetToAppDefaultEngine() { let appDefaultEngine = this.appDefaultEngine; @@ -1420,6 +1423,10 @@ export class SearchService { // We need to catch the region being updated during initialization so we // start listening straight away. Services.obs.addObserver(this, lazy.Region.REGION_TOPIC); + + this.#engineSelector = new lazy.SearchEngineSelector( + this.#handleConfigurationUpdated.bind(this) + ); } /** @@ -1652,7 +1659,6 @@ export class SearchService { * Handles the search configuration being - adds a wait on the user * being idle, before the search engine update gets handled. */ - // eslint-disable-next-line no-unused-private-class-members #handleConfigurationUpdated() { if (this.#queuedIdle) { return; @@ -2622,12 +2628,21 @@ export class SearchService { // This is prefixed with _ rather than # because it is // called in test_remove_engine_notification_box.js async _fetchEngineSelectorEngines() { - const engines = await ( - await fetch( - "chrome://global/content/search/mullvadBrowserSearchEngines.json" - ) - ).json(); - return { engines, privateDefault: undefined }; + let searchEngineSelectorProperties = { + locale: Services.locale.appLocaleAsBCP47, + region: lazy.Region.home || "unknown", + channel: lazy.SearchUtils.MODIFIED_APP_CHANNEL, + experiment: this._experimentPrefValue, + distroID: lazy.SearchUtils.distroID ?? "", + }; + + for (let [key, value] of Object.entries(searchEngineSelectorProperties)) { + this._settings.setMetaDataAttribute(key, value); + } + + return this.#engineSelector.fetchEngineConfiguration( + searchEngineSelectorProperties + ); } #setDefaultFromSelector(refinedConfig) { ===================================== toolkit/components/search/content/mullvadBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -1,27 +1,33 @@ { "ddg": [ - { "url": "chrome://global/content/search/duckduckgo.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-html": [ - { "url": "chrome://global/content/search/duckduckgo.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "mullvad-leta": [ - { "url": "chrome://global/content/search/mullvad-leta.svg", "iconSize": 16 } + { + "url": "chrome://global/content/search/mullvad-leta.svg", + "imageSize": 16 + } ], "mojeek": [ - { "url": "chrome://global/content/search/mojeek.ico", "iconSize": 32 } + { "url": "chrome://global/content/search/mojeek.ico", "imageSize": 32 } ], "brave": [ - { "url": "chrome://global/content/search/brave.svg", "iconSize": 16 } + { "url": "chrome://global/content/search/brave.svg", "imageSize": 16 } ], "startpage": [ { "url": "chrome://global/content/search/startpage-16.png", - "iconSize": 16 + "imageSize": 16 }, - { "url": "chrome://global/content/search/startpage-32.png", "iconSize": 32 } + { + "url": "chrome://global/content/search/startpage-32.png", + "imageSize": 32 + } ], "metager": [ - { "url": "chrome://global/content/search/metager.ico", "iconSize": 196 } + { "url": "chrome://global/content/search/metager.ico", "imageSize": 196 } ] } ===================================== toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -0,0 +1,133 @@ +[ + { + "base": { + "aliases": ["mullvad-leta", "leta", "mullvad", "ml"], + "classification": "general", + "name": "Mullvad Leta", + "urls": { + "search": { + "base": "https://leta.mullvad.net/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "ee88d691-6d7a-4adb-9fec-5a205565505a", + "identifier": "mullvad-leta", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["duckduckgo", "ddg"], + "classification": "general", + "name": "DuckDuckGo", + "urls": { + "search": { + "base": "https://duckduckgo.com/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", + "identifier": "ddg", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["ddg-html", "duckduckgohtml", "ddgh"], + "classification": "general", + "name": "DuckDuckGo (HTML)", + "urls": { + "search": { + "base": "https://html.duckduckgo.com/html/", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "98d8c84b-7455-431d-98b9-890e7bcc0041", + "identifier": "ddg-html", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["mojeek", "mj"], + "classification": "general", + "name": "Mojeek", + "urls": { + "search": { + "base": "https://www.mojeek.com/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "10df12ac-2b39-4aa9-8845-d5b35d5bb70c", + "identifier": "mojeek", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["brave", "bv"], + "classification": "general", + "name": "Brave Search", + "urls": { + "search": { + "base": "https://search.brave.com/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "f479314b-030b-49a8-a2fe-7e1c5d1d9071", + "identifier": "brave", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["startpage", "sp"], + "classification": "general", + "name": "Startpage", + "urls": { + "search": { + "base": "https://www.startpage.com/sp/search", + "params": [], + "searchTermParamName": "q" + } + } + }, + "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", + "identifier": "startpage", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "base": { + "aliases": ["metager", "mg"], + "classification": "general", + "name": "MetaGer", + "urls": { + "search": { + "base": "https://metager.org/meta/meta.ger3", + "params": [], + "searchTermParamName": "eingabe" + } + } + }, + "id": "a9d07d93-469c-4bf4-8dd1-fa137f1cc85f", + "identifier": "metager", + "recordType": "engine", + "variants": [{ "environment": { "allRegionsAndLocales": true } }] + }, + { + "recordType": "defaultEngines", + "globalDefault": "mullvad-leta", + "globalDefaultPrivate": "mullvad-leta" + } +] ===================================== toolkit/components/search/content/mullvadBrowserSearchEngines.json deleted ===================================== @@ -1,114 +0,0 @@ -[ - { - "aliases": ["mullvad-leta", "leta", "mullvad", "ml"], - "name": "Mullvad Leta", - "urls": { - "search": { - "base": "https://leta.mullvad.net/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "ee88d691-6d7a-4adb-9fec-5a205565505a", - "identifier": "mullvad-leta", - "recordType": "engine", - "orderHint": 100, - "variants": [] - }, - { - "aliases": ["duckduckgo", "ddg"], - "name": "DuckDuckGo", - "urls": { - "search": { - "base": "https://duckduckgo.com/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", - "identifier": "ddg", - "recordType": "engine", - "orderHint": 90, - "variants": [] - }, - { - "aliases": ["ddg-html", "duckduckgohtml", "ddgh"], - "name": "DuckDuckGo (HTML)", - "urls": { - "search": { - "base": "https://html.duckduckgo.com/html/", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "98d8c84b-7455-431d-98b9-890e7bcc0041", - "identifier": "ddg-html", - "recordType": "engine", - "orderHint": 80, - "variants": [] - }, - { - "aliases": ["mojeek", "mj"], - "name": "Mojeek", - "urls": { - "search": { - "base": "https://www.mojeek.com/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "10df12ac-2b39-4aa9-8845-d5b35d5bb70c", - "identifier": "mojeek", - "recordType": "engine", - "orderHint": 70, - "variants": [] - }, - { - "aliases": ["brave", "bv"], - "name": "Brave Search", - "urls": { - "search": { - "base": "https://search.brave.com/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "f479314b-030b-49a8-a2fe-7e1c5d1d9071", - "identifier": "brave", - "recordType": "engine", - "orderHint": 60, - "variants": [] - }, - { - "aliases": ["startpage", "sp"], - "name": "Startpage", - "urls": { - "search": { - "base": "https://www.startpage.com/sp/search", - "params": [], - "searchTermParamName": "q" - } - }, - "id": "049f86fd-28fe-4389-910f-aac28f07d745", - "identifier": "startpage", - "recordType": "engine", - "orderHint": 50, - "variants": [] - }, - { - "aliases": ["metager", "mg"], - "name": "MetaGer", - "urls": { - "search": { - "base": "https://metager.org/meta/meta.ger3", - "params": [], - "searchTermParamName": "eingabe" - } - }, - "id": "a9d07d93-469c-4bf4-8dd1-fa137f1cc85f", - "identifier": "metager", - "recordType": "engine", - "orderHint": 40, - "variants": [] - } -] View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ac… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ac… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] 3 commits: dropme! TB 42891: Set the bundled search engine for Tor Browser.
by Pier Angelo Vendrame (@pierov) 08 Sep '25

08 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: 2404a7c1 by Pier Angelo Vendrame at 2025-09-08T11:39:58+02:00 dropme! TB 42891: Set the bundled search engine for Tor Browser. BB 43525: Skip Remote Settings for search engine customization. Undo some changes to this commit, as they need to be moved to Base Browser. - - - - - 10cd8e31 by Pier Angelo Vendrame at 2025-09-08T11:39:58+02:00 BB 43525: Skip Remote Settings for search engine customization. Also, add some bundled search engines. - - - - - d28d9f49 by Pier Angelo Vendrame at 2025-09-08T11:39:59+02:00 amend! TB 42891: Set the bundled search engine for Tor Browser. TB 42891: Set the bundled search engine for Tor Browser. - - - - - 4 changed files: - toolkit/components/search/AppProvidedSearchEngine.sys.mjs - toolkit/components/search/SearchEngineSelector.sys.mjs - toolkit/components/search/content/torBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json - toolkit/components/search/content/torBrowserSearchEngines.json → toolkit/components/search/content/base-browser-search-engines.json Changes: ===================================== toolkit/components/search/AppProvidedSearchEngine.sys.mjs ===================================== @@ -116,8 +116,10 @@ class IconHandler { await this.#buildIconMap(); } - return this.#iconMap.get(engineIdentifier); - // eslint-disable-next-line no-unreachable + if (AppConstants.BASE_BROWSER_VERSION) { + return this.#iconMap.get(engineIdentifier); + } + let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) @@ -223,7 +225,7 @@ class IconHandler { Object.entries( await ( await fetch( - "chrome://global/content/search/torBrowserSearchEngineIcons.json" + "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ===================================== toolkit/components/search/SearchEngineSelector.sys.mjs ===================================== @@ -97,7 +97,9 @@ export class SearchEngineSelector { let { promise, resolve } = Promise.withResolvers(); this._getConfigurationPromise = promise; this._configuration = await ( - await fetch("chrome://global/content/search/torBrowserSearchEngines.json") + await fetch( + "chrome://global/content/search/base-browser-search-engines.json" + ) ).json(); this._configurationOverrides = []; resolve(this._configuration); ===================================== toolkit/components/search/content/torBrowserSearchEngineIcons.json → toolkit/components/search/content/base-browser-search-engine-icons.json ===================================== @@ -1,15 +1,9 @@ { "ddg": [ - { - "url": "chrome://global/content/search/duckduckgo.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-onion": [ - { - "url": "chrome://global/content/search/duckduckgo.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "startpage": [ { @@ -32,9 +26,6 @@ } ], "wikipedia": [ - { - "url": "chrome://global/content/search/wikipedia.ico", - "imageSize": 32 - } + { "url": "chrome://global/content/search/wikipedia.ico", "imageSize": 32 } ] } ===================================== toolkit/components/search/content/torBrowserSearchEngines.json → toolkit/components/search/content/base-browser-search-engines.json ===================================== @@ -15,13 +15,7 @@ "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", "identifier": "ddg", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -39,13 +33,7 @@ "id": "1e431da4-a60c-4411-9251-a95a841d451f", "identifier": "ddg-onion", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -63,13 +51,7 @@ "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", "identifier": "startpage", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -87,13 +69,7 @@ "id": "e7eaba8d-6b9e-43fb-a799-b01b096c03ff", "identifier": "startpage-onion", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { @@ -111,13 +87,7 @@ "id": "7f6d23c2-191e-483e-af3a-ce6451e3a8dd", "identifier": "wikipedia", "recordType": "engine", - "variants": [ - { - "environment": { - "allRegionsAndLocales": true - } - } - ] + "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "recordType": "defaultEngines", View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d244ff… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d244ff… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/mullvad-browser][mullvad-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch mullvad-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser Commits: ac67b549 by Pier Angelo Vendrame at 2025-09-05T18:56:43+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ac6… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ac6… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][base-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d0b3fa67 by Pier Angelo Vendrame at 2025-09-05T18:56:10+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d0b3fa6… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d0b3fa6… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
[Git][tpo/applications/tor-browser][tor-browser-140.2.0esr-15.0-1] BB 43664: Automatically check the PBM checkbox when in always-on PBM.
by Pier Angelo Vendrame (@pierov) 05 Sep '25

05 Sep '25
Pier Angelo Vendrame pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser Commits: d244ff5a by Pier Angelo Vendrame at 2025-09-04T18:30:26+02:00 BB 43664: Automatically check the PBM checkbox when in always-on PBM. - - - - - 1 changed file: - browser/base/content/browser-addons.js Changes: ===================================== browser/base/content/browser-addons.js ===================================== @@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, { ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", OriginControls: "resource://gre/modules/ExtensionPermissions.sys.mjs", PERMISSION_L10N: "resource://gre/modules/ExtensionPermissionMessages.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SITEPERMS_ADDON_TYPE: "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs", }); @@ -466,7 +467,9 @@ customElements.define( this.notification.options.customElementOptions; let checkboxEl = this.ownerDocument.createElement("moz-checkbox"); - checkboxEl.checked = grantPrivateBrowsingAllowed; + checkboxEl.checked = + grantPrivateBrowsingAllowed || + lazy.PrivateBrowsingUtils.permanentPrivateBrowsing; checkboxEl.addEventListener("change", () => { // NOTE: the popupnotification instances will be reused // and so the callback function is destructured here to View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d244ff5… -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d244ff5… You're receiving this email because of your account on gitlab.torproject.org.
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • ...
  • 2005
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.