
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/a1886d8... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a1886d8... You're receiving this email because of your account on gitlab.torproject.org.
participants (1)
-
Pier Angelo Vendrame (@pierov)