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
-
d4c6e7a4
by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00
-
8eccdc93
by Pier Angelo Vendrame at 2025-09-08T12:03:35+02:00
-
167c0116
by Pier Angelo Vendrame at 2025-09-08T12:03:36+02:00
-
b45bb7f1
by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00
-
ad267a06
by Pier Angelo Vendrame at 2025-09-08T12:03:37+02:00
-
a05bd724
by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00
-
a857af7e
by Pier Angelo Vendrame at 2025-09-08T12:03:38+02:00
-
51ca3bdf
by Pier Angelo Vendrame at 2025-09-08T12:03:39+02:00
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:
| ... | ... | @@ -51,6 +51,11 @@ category browser-first-window-ready resource://gre/modules/CaptchaDetectionPingU |
| 51 | 51 | category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs SandboxUtils.maybeWarnAboutMissingUserNamespaces
|
| 52 | 52 | #endif
|
| 53 | 53 | #endif
|
| 54 | +category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init
|
|
| 55 | +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready
|
|
| 56 | +category browser-first-window-ready moz-src:///toolkit/modules/DragDropFilter.sys.mjs DragDropFilter.init
|
|
| 57 | +category browser-first-window-ready moz-src:///browser/modules/TorSettingsNotification.sys.mjs TorSettingsNotification.ready
|
|
| 58 | +category browser-first-window-ready moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.init
|
|
| 54 | 59 | |
| 55 | 60 | category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars
|
| 56 | 61 | 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 |
| 94 | 99 | category browser-quit-application-granted resource://gre/modules/UpdateListener.sys.mjs UpdateListener.reset
|
| 95 | 100 | #endif
|
| 96 | 101 | category browser-quit-application-granted resource:///modules/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit
|
| 102 | +category browser-quit-application-granted moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.uninit
|
|
| 97 | 103 | |
| 98 | 104 | category search-service-notification moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchUIUtils.showSearchServiceNotification |
| ... | ... | @@ -12,7 +12,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 12 | 12 | AWToolbarButton: "resource:///modules/aboutwelcome/AWToolbarUtils.sys.mjs",
|
| 13 | 13 | ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs",
|
| 14 | 14 | AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
|
| 15 | - AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
|
|
| 16 | 15 | BackupService: "resource:///modules/backup/BackupService.sys.mjs",
|
| 17 | 16 | BrowserSearchTelemetry:
|
| 18 | 17 | "moz-src:///browser/components/search/BrowserSearchTelemetry.sys.mjs",
|
| ... | ... | @@ -31,7 +30,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 31 | 30 | DistributionManagement: "resource:///modules/distribution.sys.mjs",
|
| 32 | 31 | DownloadsViewableInternally:
|
| 33 | 32 | "resource:///modules/DownloadsViewableInternally.sys.mjs",
|
| 34 | - DragDropFilter: "resource://gre/modules/DragDropFilter.sys.mjs",
|
|
| 35 | 33 | ExtensionsUI: "resource:///modules/ExtensionsUI.sys.mjs",
|
| 36 | 34 | // FilePickerCrashed is used by the `listeners` object below.
|
| 37 | 35 | // eslint-disable-next-line mozilla/valid-lazy
|
| ... | ... | @@ -42,7 +40,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 42 | 40 | LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
|
| 43 | 41 | MigrationUtils: "resource:///modules/MigrationUtils.sys.mjs",
|
| 44 | 42 | NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
|
| 45 | - OnionAliasStore: "resource:///modules/OnionAliasStore.sys.mjs",
|
|
| 46 | 43 | OnboardingMessageProvider:
|
| 47 | 44 | "resource:///modules/asrouter/OnboardingMessageProvider.sys.mjs",
|
| 48 | 45 | PageDataService: "resource:///modules/pagedata/PageDataService.sys.mjs",
|
| ... | ... | @@ -63,8 +60,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 63 | 60 | ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs",
|
| 64 | 61 | SearchSERPTelemetry:
|
| 65 | 62 | "moz-src:///browser/components/search/SearchSERPTelemetry.sys.mjs",
|
| 66 | - SecurityLevelRestartNotification:
|
|
| 67 | - "resource:///modules/SecurityLevelRestartNotification.sys.mjs",
|
|
| 68 | 63 | SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
|
| 69 | 64 | SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
| 70 | 65 | ShortcutUtils: "resource://gre/modules/ShortcutUtils.sys.mjs",
|
| ... | ... | @@ -75,11 +70,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 75 | 70 | TelemetryReportingPolicy:
|
| 76 | 71 | "resource://gre/modules/TelemetryReportingPolicy.sys.mjs",
|
| 77 | 72 | TRRRacer: "resource:///modules/TRRPerformance.sys.mjs",
|
| 78 | - TorConnect: "resource://gre/modules/TorConnect.sys.mjs",
|
|
| 79 | - TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs",
|
|
| 80 | - TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
|
| 81 | - TorSettingsNotification:
|
|
| 82 | - "resource:///modules/TorSettingsNotification.sys.mjs",
|
|
| 83 | 73 | WebChannel: "resource://gre/modules/WebChannel.sys.mjs",
|
| 84 | 74 | WebProtocolHandlerRegistrar:
|
| 85 | 75 | "resource:///modules/WebProtocolHandlerRegistrar.sys.mjs",
|
| ... | ... | @@ -113,170 +103,6 @@ if (AppConstants.ENABLE_WEBDRIVER) { |
| 113 | 103 | |
| 114 | 104 | const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state";
|
| 115 | 105 | |
| 116 | -// Empty clipboard content from private windows on exit
|
|
| 117 | -// (tor-browser#42154)
|
|
| 118 | -const ClipboardPrivacy = {
|
|
| 119 | - _lastClipboardHash: null,
|
|
| 120 | - _globalActivation: false,
|
|
| 121 | - _isPrivateClipboard: false,
|
|
| 122 | - _hasher: null,
|
|
| 123 | - _shuttingDown: false,
|
|
| 124 | - _log: null,
|
|
| 125 | - |
|
| 126 | - _createTransferable() {
|
|
| 127 | - const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
|
| 128 | - Ci.nsITransferable
|
|
| 129 | - );
|
|
| 130 | - trans.init(null);
|
|
| 131 | - return trans;
|
|
| 132 | - },
|
|
| 133 | - _computeClipboardHash() {
|
|
| 134 | - const flavors = ["text/x-moz-url", "text/plain"];
|
|
| 135 | - if (
|
|
| 136 | - !Services.clipboard.hasDataMatchingFlavors(
|
|
| 137 | - flavors,
|
|
| 138 | - Ci.nsIClipboard.kGlobalClipboard
|
|
| 139 | - )
|
|
| 140 | - ) {
|
|
| 141 | - return null;
|
|
| 142 | - }
|
|
| 143 | - const trans = this._createTransferable();
|
|
| 144 | - flavors.forEach(trans.addDataFlavor);
|
|
| 145 | - try {
|
|
| 146 | - Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard);
|
|
| 147 | - const clipboardContent = {};
|
|
| 148 | - trans.getAnyTransferData({}, clipboardContent);
|
|
| 149 | - const { data } = clipboardContent.value.QueryInterface(
|
|
| 150 | - Ci.nsISupportsString
|
|
| 151 | - );
|
|
| 152 | - const bytes = new TextEncoder().encode(data);
|
|
| 153 | - const hasher = (this._hasher ||= Cc[
|
|
| 154 | - "@mozilla.org/security/hash;1"
|
|
| 155 | - ].createInstance(Ci.nsICryptoHash));
|
|
| 156 | - hasher.init(hasher.SHA256);
|
|
| 157 | - hasher.update(bytes, bytes.length);
|
|
| 158 | - return hasher.finish(true);
|
|
| 159 | - } catch (e) {}
|
|
| 160 | - return null;
|
|
| 161 | - },
|
|
| 162 | - |
|
| 163 | - startup() {
|
|
| 164 | - this._log = console.createInstance({
|
|
| 165 | - prefix: "ClipboardPrivacy",
|
|
| 166 | - });
|
|
| 167 | - this._lastClipboardHash = this._computeClipboardHash();
|
|
| 168 | - |
|
| 169 | - // Here we track changes in active window / application,
|
|
| 170 | - // by filtering focus events and window closures.
|
|
| 171 | - const handleActivation = (win, activation) => {
|
|
| 172 | - if (activation) {
|
|
| 173 | - if (!this._globalActivation) {
|
|
| 174 | - // focus changed within this window, bail out.
|
|
| 175 | - return;
|
|
| 176 | - }
|
|
| 177 | - this._globalActivation = false;
|
|
| 178 | - } else if (!Services.focus.activeWindow) {
|
|
| 179 | - // focus is leaving this window:
|
|
| 180 | - // let's track whether it remains within the browser.
|
|
| 181 | - lazy.setTimeout(() => {
|
|
| 182 | - this._globalActivation = !Services.focus.activeWindow;
|
|
| 183 | - }, 100);
|
|
| 184 | - }
|
|
| 185 | - |
|
| 186 | - const checkClipboardContent = () => {
|
|
| 187 | - const clipboardHash = this._computeClipboardHash();
|
|
| 188 | - if (clipboardHash !== this._lastClipboardHash) {
|
|
| 189 | - this._isPrivateClipboard =
|
|
| 190 | - !activation &&
|
|
| 191 | - (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
|
| 192 | - lazy.PrivateBrowsingUtils.isWindowPrivate(win));
|
|
| 193 | - this._lastClipboardHash = clipboardHash;
|
|
| 194 | - this._log.debug(
|
|
| 195 | - `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.`
|
|
| 196 | - );
|
|
| 197 | - }
|
|
| 198 | - };
|
|
| 199 | - |
|
| 200 | - if (win.closed) {
|
|
| 201 | - checkClipboardContent();
|
|
| 202 | - } else {
|
|
| 203 | - // defer clipboard access on DOM events to work-around tor-browser#42306
|
|
| 204 | - lazy.setTimeout(checkClipboardContent, 0);
|
|
| 205 | - }
|
|
| 206 | - };
|
|
| 207 | - const focusListener = e =>
|
|
| 208 | - e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin");
|
|
| 209 | - const initWindow = win => {
|
|
| 210 | - for (const e of ["focusin", "focusout"]) {
|
|
| 211 | - win.addEventListener(e, focusListener);
|
|
| 212 | - }
|
|
| 213 | - };
|
|
| 214 | - for (const w of Services.ww.getWindowEnumerator()) {
|
|
| 215 | - initWindow(w);
|
|
| 216 | - }
|
|
| 217 | - Services.ww.registerNotification((win, event) => {
|
|
| 218 | - switch (event) {
|
|
| 219 | - case "domwindowopened":
|
|
| 220 | - initWindow(win);
|
|
| 221 | - break;
|
|
| 222 | - case "domwindowclosed":
|
|
| 223 | - handleActivation(win, false);
|
|
| 224 | - if (
|
|
| 225 | - this._isPrivateClipboard &&
|
|
| 226 | - lazy.PrivateBrowsingUtils.isWindowPrivate(win) &&
|
|
| 227 | - (this._shuttingDown ||
|
|
| 228 | - !Array.from(Services.ww.getWindowEnumerator()).find(
|
|
| 229 | - w =>
|
|
| 230 | - lazy.PrivateBrowsingUtils.isWindowPrivate(w) &&
|
|
| 231 | - // We need to filter out the HIDDEN WebExtensions window,
|
|
| 232 | - // which might be private as well but is not UI-relevant.
|
|
| 233 | - !w.location.href.startsWith("chrome://extensions/")
|
|
| 234 | - ))
|
|
| 235 | - ) {
|
|
| 236 | - // no more private windows, empty private content if needed
|
|
| 237 | - this.emptyPrivate();
|
|
| 238 | - }
|
|
| 239 | - }
|
|
| 240 | - });
|
|
| 241 | - |
|
| 242 | - lazy.AsyncShutdown.quitApplicationGranted.addBlocker(
|
|
| 243 | - "ClipboardPrivacy: removing private data",
|
|
| 244 | - () => {
|
|
| 245 | - this._shuttingDown = true;
|
|
| 246 | - this.emptyPrivate();
|
|
| 247 | - }
|
|
| 248 | - );
|
|
| 249 | - },
|
|
| 250 | - emptyPrivate() {
|
|
| 251 | - if (
|
|
| 252 | - this._isPrivateClipboard &&
|
|
| 253 | - !Services.prefs.getBoolPref(
|
|
| 254 | - "browser.privatebrowsing.preserveClipboard",
|
|
| 255 | - false
|
|
| 256 | - ) &&
|
|
| 257 | - this._lastClipboardHash === this._computeClipboardHash()
|
|
| 258 | - ) {
|
|
| 259 | - // nsIClipboard.emptyClipboard() does nothing in Wayland:
|
|
| 260 | - // we'll set an empty string as a work-around.
|
|
| 261 | - const trans = this._createTransferable();
|
|
| 262 | - const flavor = "text/plain";
|
|
| 263 | - trans.addDataFlavor(flavor);
|
|
| 264 | - const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance(
|
|
| 265 | - Ci.nsISupportsString
|
|
| 266 | - );
|
|
| 267 | - emptyString.data = "";
|
|
| 268 | - trans.setTransferData(flavor, emptyString);
|
|
| 269 | - const { clipboard } = Services,
|
|
| 270 | - { kGlobalClipboard } = clipboard;
|
|
| 271 | - clipboard.setData(trans, null, kGlobalClipboard);
|
|
| 272 | - clipboard.emptyClipboard(kGlobalClipboard);
|
|
| 273 | - this._lastClipboardHash = null;
|
|
| 274 | - this._isPrivateClipboard = false;
|
|
| 275 | - this._log.info("Private clipboard emptied.");
|
|
| 276 | - }
|
|
| 277 | - },
|
|
| 278 | -};
|
|
| 279 | - |
|
| 280 | 106 | ChromeUtils.defineLazyGetter(
|
| 281 | 107 | lazy,
|
| 282 | 108 | "WeaveService",
|
| ... | ... | @@ -603,13 +429,8 @@ BrowserGlue.prototype = { |
| 603 | 429 | |
| 604 | 430 | // handle any UI migration
|
| 605 | 431 | this._migrateUI();
|
| 606 | - |
|
| 607 | - // Base Browser-specific version of _migrateUI.
|
|
| 608 | - this._migrateUIBB();
|
|
| 609 | - |
|
| 610 | - // Handle any TBB-specific migration before showing the UI. Keep after
|
|
| 611 | - // _migrateUI to make sure this._isNewProfile has been defined.
|
|
| 612 | - this._migrateUITBB();
|
|
| 432 | + lazy.ProfileDataUpgrader.upgradeBB(this._isNewProfile);
|
|
| 433 | + lazy.ProfileDataUpgrader.upgradeTB(this._isNewProfile);
|
|
| 613 | 434 | |
| 614 | 435 | if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) {
|
| 615 | 436 | lazy.PdfJs.checkIsDefault(this._isNewProfile);
|
| ... | ... | @@ -995,16 +816,6 @@ BrowserGlue.prototype = { |
| 995 | 816 | lazy.WeaveService.init();
|
| 996 | 817 | }
|
| 997 | 818 | |
| 998 | - lazy.SecurityLevelRestartNotification.ready();
|
|
| 999 | - |
|
| 1000 | - lazy.DragDropFilter.init();
|
|
| 1001 | - |
|
| 1002 | - lazy.TorProviderBuilder.firstWindowLoaded();
|
|
| 1003 | - |
|
| 1004 | - lazy.TorSettingsNotification.ready();
|
|
| 1005 | - |
|
| 1006 | - ClipboardPrivacy.startup();
|
|
| 1007 | - |
|
| 1008 | 819 | lazy.BrowserUtils.callModulesFromCategory(
|
| 1009 | 820 | {
|
| 1010 | 821 | categoryName: "browser-first-window-ready",
|
| ... | ... | @@ -1104,7 +915,6 @@ BrowserGlue.prototype = { |
| 1104 | 915 | // can perform at-shutdown tasks later in shutdown.
|
| 1105 | 916 | Services.fog;
|
| 1106 | 917 | },
|
| 1107 | - () => lazy.OnionAliasStore.uninit(),
|
|
| 1108 | 918 | ];
|
| 1109 | 919 | |
| 1110 | 920 | for (let task of tasks) {
|
| ... | ... | @@ -1375,30 +1185,6 @@ BrowserGlue.prototype = { |
| 1375 | 1185 | },
|
| 1376 | 1186 | },
|
| 1377 | 1187 | |
| 1378 | - {
|
|
| 1379 | - task: () => {
|
|
| 1380 | - if (!lazy.TorConnect.shouldShowTorConnect) {
|
|
| 1381 | - // we will take this path when the user is using the legacy tor launcher or
|
|
| 1382 | - // when Tor Browser didn't launch its own tor.
|
|
| 1383 | - lazy.OnionAliasStore.init();
|
|
| 1384 | - } else {
|
|
| 1385 | - // this path is taken when using about:torconnect, we wait to init
|
|
| 1386 | - // after we are bootstrapped and connected to tor
|
|
| 1387 | - const topic = lazy.TorConnectTopics.BootstrapComplete;
|
|
| 1388 | - let bootstrapObserver = {
|
|
| 1389 | - observe(aSubject, aTopic) {
|
|
| 1390 | - if (aTopic === topic) {
|
|
| 1391 | - lazy.OnionAliasStore.init();
|
|
| 1392 | - // we only need to init once, so remove ourselves as an obvserver
|
|
| 1393 | - Services.obs.removeObserver(this, topic);
|
|
| 1394 | - }
|
|
| 1395 | - },
|
|
| 1396 | - };
|
|
| 1397 | - Services.obs.addObserver(bootstrapObserver, topic);
|
|
| 1398 | - }
|
|
| 1399 | - },
|
|
| 1400 | - },
|
|
| 1401 | - |
|
| 1402 | 1188 | // Run TRR performance measurements for DoH.
|
| 1403 | 1189 | {
|
| 1404 | 1190 | name: "doh-rollout.trrRacer.run",
|
| ... | ... | @@ -1865,208 +1651,6 @@ BrowserGlue.prototype = { |
| 1865 | 1651 | }
|
| 1866 | 1652 | },
|
| 1867 | 1653 | |
| 1868 | - _migrateUIBB() {
|
|
| 1869 | - // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override
|
|
| 1870 | - // for tor-browser#41739.
|
|
| 1871 | - // Version 2: 14.0a5: Reset the privacy tracking headers preferences since
|
|
| 1872 | - // the UI is hidden. tor-browser#42777.
|
|
| 1873 | - // Also, do not set
|
|
| 1874 | - // dom.security.https_only_mode_send_http_background_request in
|
|
| 1875 | - // the security level anymore (tor-browser#42149).
|
|
| 1876 | - // Also, reset security.xfocsp.errorReporting.automatic since we
|
|
| 1877 | - // hid its neterror checkbox. tor-browser#42653.
|
|
| 1878 | - // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070.
|
|
| 1879 | - // Version 4: 15.0a2: Drop ML components. tor-browser#44045.
|
|
| 1880 | - const MIGRATION_VERSION = 4;
|
|
| 1881 | - const MIGRATION_PREF = "basebrowser.migration.version";
|
|
| 1882 | - if (this._isNewProfile) {
|
|
| 1883 | - // Do not migrate fresh profiles
|
|
| 1884 | - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION);
|
|
| 1885 | - return;
|
|
| 1886 | - } else if (this._isNewProfile === undefined) {
|
|
| 1887 | - // If this happens, check if upstream updated their function and do not
|
|
| 1888 | - // set this member anymore!
|
|
| 1889 | - console.error("_migrateUIBB: this._isNewProfile is undefined.");
|
|
| 1890 | - }
|
|
| 1891 | - // We do not care whether this is a new or old profile, since in version 1
|
|
| 1892 | - // we just quickly clear a user preference, which should not do anything to
|
|
| 1893 | - // new profiles.
|
|
| 1894 | - // Shall we ever raise the version number and have a watershed, we can add
|
|
| 1895 | - // a check easily (any version > 0 will be an old profile).
|
|
| 1896 | - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0);
|
|
| 1897 | - if (currentVersion < 1) {
|
|
| 1898 | - Services.prefs.clearUserPref(
|
|
| 1899 | - "layout.css.prefers-color-scheme.content-override"
|
|
| 1900 | - );
|
|
| 1901 | - }
|
|
| 1902 | - if (currentVersion < 2) {
|
|
| 1903 | - for (const prefName of [
|
|
| 1904 | - "privacy.globalprivacycontrol.enabled",
|
|
| 1905 | - "privacy.donottrackheader.enabled",
|
|
| 1906 | - // Telemetry preference for if the user changed the value.
|
|
| 1907 | - "privacy.globalprivacycontrol.was_ever_enabled",
|
|
| 1908 | - // The next two preferences have no corresponding UI, but are related.
|
|
| 1909 | - "privacy.globalprivacycontrol.functionality.enabled",
|
|
| 1910 | - "privacy.globalprivacycontrol.pbmode.enabled",
|
|
| 1911 | - "dom.security.https_only_mode_send_http_background_request",
|
|
| 1912 | - "security.xfocsp.errorReporting.automatic",
|
|
| 1913 | - ]) {
|
|
| 1914 | - Services.prefs.clearUserPref(prefName);
|
|
| 1915 | - }
|
|
| 1916 | - }
|
|
| 1917 | - if (currentVersion < 3) {
|
|
| 1918 | - Services.prefs.clearUserPref("general.smoothScroll");
|
|
| 1919 | - }
|
|
| 1920 | - if (currentVersion < 4) {
|
|
| 1921 | - for (const prefName of [
|
|
| 1922 | - "browser.translations.enable",
|
|
| 1923 | - "browser.ml.enable",
|
|
| 1924 | - "browser.ml.chat.enabled",
|
|
| 1925 | - "browser.ml.linkPreview.enabled",
|
|
| 1926 | - "browser.tabs.groups.smart.enabled",
|
|
| 1927 | - "browser.tabs.groups.smart.userEnabled",
|
|
| 1928 | - "extensions.ml.enabled",
|
|
| 1929 | - "pdfjs.enableAltText",
|
|
| 1930 | - "pdfjs.enableAltTextForEnglish",
|
|
| 1931 | - "pdfjs.enableGuessAltText",
|
|
| 1932 | - "pdfjs.enableAltTextModelDownload",
|
|
| 1933 | - "browser.urlbar.quicksuggest.mlEnabled",
|
|
| 1934 | - "places.semanticHistory.featureGate",
|
|
| 1935 | - ]) {
|
|
| 1936 | - // Preferences are locked. Do not want user values to linger in the
|
|
| 1937 | - // user's profile and become active if these preferences become unlocked
|
|
| 1938 | - // in the future.
|
|
| 1939 | - Services.prefs.clearUserPref(prefName);
|
|
| 1940 | - }
|
|
| 1941 | - }
|
|
| 1942 | - Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION);
|
|
| 1943 | - },
|
|
| 1944 | - |
|
| 1945 | - // Use this method for any TBB migration that can be run just before showing
|
|
| 1946 | - // the UI.
|
|
| 1947 | - // Anything that critically needs to be migrated earlier should not use this.
|
|
| 1948 | - async _migrateUITBB() {
|
|
| 1949 | - // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the
|
|
| 1950 | - // migration to packaged locales.
|
|
| 1951 | - // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some
|
|
| 1952 | - // torbutton preferences that are not used anymore.
|
|
| 1953 | - // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair
|
|
| 1954 | - // (tor-browser#42283).
|
|
| 1955 | - // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and
|
|
| 1956 | - // YouTube search engines (tor-browser#41835).
|
|
| 1957 | - // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings
|
|
| 1958 | - // since we hid the UI (tor-browser#43118).
|
|
| 1959 | - // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is
|
|
| 1960 | - // no longer used (tor-browser#41921).
|
|
| 1961 | - // Drop unused TorConnect setting (tor-browser#43462).
|
|
| 1962 | - // Version 7: Tor Browser 14.5a6: Clear home page update url preference
|
|
| 1963 | - // (tor-browser#43567).
|
|
| 1964 | - // Version 8: Tor Browser 15.0a2: Remove legacy search addons
|
|
| 1965 | - // (tor-browser#43111).
|
|
| 1966 | - const TBB_MIGRATION_VERSION = 8;
|
|
| 1967 | - const MIGRATION_PREF = "torbrowser.migration.version";
|
|
| 1968 | - |
|
| 1969 | - // If we decide to force updating users to pass through any version
|
|
| 1970 | - // following 12.0, we can remove this check, and check only whether
|
|
| 1971 | - // MIGRATION_PREF has a user value, like Mozilla does.
|
|
| 1972 | - if (this._isNewProfile) {
|
|
| 1973 | - // Do not migrate fresh profiles
|
|
| 1974 | - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION);
|
|
| 1975 | - return;
|
|
| 1976 | - } else if (this._isNewProfile === undefined) {
|
|
| 1977 | - // If this happens, check if upstream updated their function and do not
|
|
| 1978 | - // set this member anymore!
|
|
| 1979 | - console.error("_migrateUITBB: this._isNewProfile is undefined.");
|
|
| 1980 | - }
|
|
| 1981 | - |
|
| 1982 | - const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0);
|
|
| 1983 | - const removeLangpacks = async () => {
|
|
| 1984 | - for (const addon of await AddonManager.getAddonsByTypes(["locale"])) {
|
|
| 1985 | - await addon.uninstall();
|
|
| 1986 | - }
|
|
| 1987 | - };
|
|
| 1988 | - if (currentVersion < 1) {
|
|
| 1989 | - try {
|
|
| 1990 | - await removeLangpacks();
|
|
| 1991 | - } catch (err) {
|
|
| 1992 | - console.error("Could not remove langpacks", err);
|
|
| 1993 | - }
|
|
| 1994 | - }
|
|
| 1995 | - if (currentVersion < 2) {
|
|
| 1996 | - const prefToClear = [
|
|
| 1997 | - // tor-browser#41845: We were forcing these value by check the value of
|
|
| 1998 | - // automatic PBM. We decided not to change
|
|
| 1999 | - "browser.cache.disk.enable",
|
|
| 2000 | - "places.history.enabled",
|
|
| 2001 | - "security.nocertdb",
|
|
| 2002 | - "permissions.memory_only",
|
|
| 2003 | - // Old torbutton preferences not used anymore.
|
|
| 2004 | - "extensions.torbutton.loglevel",
|
|
| 2005 | - "extensions.torbutton.logmethod",
|
|
| 2006 | - "extensions.torbutton.pref_fixup_version",
|
|
| 2007 | - "extensions.torbutton.resize_new_windows",
|
|
| 2008 | - "extensions.torbutton.startup",
|
|
| 2009 | - "extensions.torlauncher.prompt_for_locale",
|
|
| 2010 | - "extensions.torlauncher.loglevel",
|
|
| 2011 | - "extensions.torlauncher.logmethod",
|
|
| 2012 | - "extensions.torlauncher.torrc_fixup_version",
|
|
| 2013 | - ];
|
|
| 2014 | - for (const pref of prefToClear) {
|
|
| 2015 | - if (Services.prefs.prefHasUserValue(pref)) {
|
|
| 2016 | - Services.prefs.clearUserPref(pref);
|
|
| 2017 | - }
|
|
| 2018 | - }
|
|
| 2019 | - }
|
|
| 2020 | - const dropAddons = async list => {
|
|
| 2021 | - for (const id of list) {
|
|
| 2022 | - try {
|
|
| 2023 | - const engine = await lazy.AddonManager.getAddonByID(id);
|
|
| 2024 | - await engine?.uninstall();
|
|
| 2025 | - } catch {}
|
|
| 2026 | - }
|
|
| 2027 | - };
|
|
| 2028 | - if (currentVersion < 3) {
|
|
| 2029 | - await dropAddons([
|
|
| 2030 | - "blockchair@search.mozilla.org",
|
|
| 2031 | - "blockchair-onion@search.mozilla.org",
|
|
| 2032 | - ]);
|
|
| 2033 | - }
|
|
| 2034 | - if (currentVersion < 4) {
|
|
| 2035 | - await dropAddons([
|
|
| 2036 | - "twitter@search.mozilla.org",
|
|
| 2037 | - "yahoo@search.mozilla.org",
|
|
| 2038 | - "youtube@search.mozilla.org",
|
|
| 2039 | - ]);
|
|
| 2040 | - }
|
|
| 2041 | - if (currentVersion < 5) {
|
|
| 2042 | - for (const pref of [
|
|
| 2043 | - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
|
|
| 2044 | - "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
|
|
| 2045 | - ]) {
|
|
| 2046 | - Services.prefs.clearUserPref(pref);
|
|
| 2047 | - }
|
|
| 2048 | - }
|
|
| 2049 | - if (currentVersion < 6) {
|
|
| 2050 | - Services.prefs.clearUserPref("torbrowser.settings.enabled");
|
|
| 2051 | - Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test");
|
|
| 2052 | - }
|
|
| 2053 | - if (currentVersion < 7) {
|
|
| 2054 | - Services.prefs.clearUserPref("torbrowser.post_update.url");
|
|
| 2055 | - }
|
|
| 2056 | - if (currentVersion < 8) {
|
|
| 2057 | - await dropAddons([
|
|
| 2058 | - "ddg@search.mozilla.org",
|
|
| 2059 | - "ddg-onion@search.mozilla.org",
|
|
| 2060 | - "google@search.mozilla.org",
|
|
| 2061 | - "startpage@search.mozilla.org",
|
|
| 2062 | - "startpage-onion@search.mozilla.org",
|
|
| 2063 | - "wikipedia@search.mozilla.org",
|
|
| 2064 | - ]);
|
|
| 2065 | - }
|
|
| 2066 | - |
|
| 2067 | - Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION);
|
|
| 2068 | - },
|
|
| 2069 | - |
|
| 2070 | 1654 | async _showUpgradeDialog() {
|
| 2071 | 1655 | const data = await lazy.OnboardingMessageProvider.getUpgradeMessage();
|
| 2072 | 1656 | const { gBrowser } = lazy.BrowserWindowTracker.getTopWindow();
|
| ... | ... | @@ -900,4 +900,200 @@ export let ProfileDataUpgrader = { |
| 900 | 900 | // Update the migration version.
|
| 901 | 901 | Services.prefs.setIntPref("browser.migration.version", newVersion);
|
| 902 | 902 | },
|
| 903 | + |
|
| 904 | + upgradeBB(isNewProfile) {
|
|
| 905 | + // Version 1: 13.0a3. Reset layout.css.prefers-color-scheme.content-override
|
|
| 906 | + // for tor-browser#41739.
|
|
| 907 | + // Version 2: 14.0a5: Reset the privacy tracking headers preferences since
|
|
| 908 | + // the UI is hidden. tor-browser#42777.
|
|
| 909 | + // Also, do not set
|
|
| 910 | + // dom.security.https_only_mode_send_http_background_request in
|
|
| 911 | + // the security level anymore (tor-browser#42149).
|
|
| 912 | + // Also, reset security.xfocsp.errorReporting.automatic since we
|
|
| 913 | + // hid its neterror checkbox. tor-browser#42653.
|
|
| 914 | + // Version 3: 14.0a7: Reset general.smoothScroll. tor-browser#42070.
|
|
| 915 | + // Version 4: 15.0a2: Drop ML components. tor-browser#44045.
|
|
| 916 | + const MIGRATION_VERSION = 4;
|
|
| 917 | + const MIGRATION_PREF = "basebrowser.migration.version";
|
|
| 918 | + |
|
| 919 | + if (isNewProfile) {
|
|
| 920 | + // Do not migrate fresh profiles
|
|
| 921 | + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION);
|
|
| 922 | + return;
|
|
| 923 | + } else if (isNewProfile === undefined) {
|
|
| 924 | + // If this happens, check if upstream updated their function and do not
|
|
| 925 | + // set this member anymore!
|
|
| 926 | + console.error("upgradeBB: isNewProfile is undefined.");
|
|
| 927 | + }
|
|
| 928 | + |
|
| 929 | + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0);
|
|
| 930 | + if (currentVersion < 1) {
|
|
| 931 | + Services.prefs.clearUserPref(
|
|
| 932 | + "layout.css.prefers-color-scheme.content-override"
|
|
| 933 | + );
|
|
| 934 | + }
|
|
| 935 | + if (currentVersion < 2) {
|
|
| 936 | + for (const prefName of [
|
|
| 937 | + "privacy.globalprivacycontrol.enabled",
|
|
| 938 | + "privacy.donottrackheader.enabled",
|
|
| 939 | + // Telemetry preference for if the user changed the value.
|
|
| 940 | + "privacy.globalprivacycontrol.was_ever_enabled",
|
|
| 941 | + // The next two preferences have no corresponding UI, but are related.
|
|
| 942 | + "privacy.globalprivacycontrol.functionality.enabled",
|
|
| 943 | + "privacy.globalprivacycontrol.pbmode.enabled",
|
|
| 944 | + "dom.security.https_only_mode_send_http_background_request",
|
|
| 945 | + "security.xfocsp.errorReporting.automatic",
|
|
| 946 | + ]) {
|
|
| 947 | + Services.prefs.clearUserPref(prefName);
|
|
| 948 | + }
|
|
| 949 | + }
|
|
| 950 | + if (currentVersion < 3) {
|
|
| 951 | + Services.prefs.clearUserPref("general.smoothScroll");
|
|
| 952 | + }
|
|
| 953 | + if (currentVersion < 4) {
|
|
| 954 | + for (const prefName of [
|
|
| 955 | + "browser.translations.enable",
|
|
| 956 | + "browser.ml.enable",
|
|
| 957 | + "browser.ml.chat.enabled",
|
|
| 958 | + "browser.ml.linkPreview.enabled",
|
|
| 959 | + "browser.tabs.groups.smart.enabled",
|
|
| 960 | + "browser.tabs.groups.smart.userEnabled",
|
|
| 961 | + "extensions.ml.enabled",
|
|
| 962 | + "pdfjs.enableAltText",
|
|
| 963 | + "pdfjs.enableAltTextForEnglish",
|
|
| 964 | + "pdfjs.enableGuessAltText",
|
|
| 965 | + "pdfjs.enableAltTextModelDownload",
|
|
| 966 | + "browser.urlbar.quicksuggest.mlEnabled",
|
|
| 967 | + "places.semanticHistory.featureGate",
|
|
| 968 | + ]) {
|
|
| 969 | + // Preferences are locked. Do not want user values to linger in the
|
|
| 970 | + // user's profile and become active if these preferences become unlocked
|
|
| 971 | + // in the future.
|
|
| 972 | + Services.prefs.clearUserPref(prefName);
|
|
| 973 | + }
|
|
| 974 | + }
|
|
| 975 | + Services.prefs.setIntPref(MIGRATION_PREF, MIGRATION_VERSION);
|
|
| 976 | + },
|
|
| 977 | + |
|
| 978 | + async upgradeTB(isNewProfile) {
|
|
| 979 | + // Version 1: Tor Browser 12.0. We use it to remove langpacks, after the
|
|
| 980 | + // migration to packaged locales.
|
|
| 981 | + // Version 2: Tor Browser 13.0/13.0a1: tor-browser#41845. Also, removed some
|
|
| 982 | + // torbutton preferences that are not used anymore.
|
|
| 983 | + // Version 3: Tor Browser 13.0.7/13.5a3: Remove blockchair
|
|
| 984 | + // (tor-browser#42283).
|
|
| 985 | + // Version 4: Tor Browser 14.0a4 (2024-09-02): Remove Twitter, Yahoo and
|
|
| 986 | + // YouTube search engines (tor-browser#41835).
|
|
| 987 | + // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings
|
|
| 988 | + // since we hid the UI (tor-browser#43118).
|
|
| 989 | + // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is
|
|
| 990 | + // no longer used (tor-browser#41921).
|
|
| 991 | + // Drop unused TorConnect setting (tor-browser#43462).
|
|
| 992 | + // Version 7: Tor Browser 14.5a6: Clear home page update url preference
|
|
| 993 | + // (tor-browser#43567).
|
|
| 994 | + // Version 8: Tor Browser 15.0a2: Remove legacy search addons
|
|
| 995 | + // (tor-browser#43111).
|
|
| 996 | + const TBB_MIGRATION_VERSION = 8;
|
|
| 997 | + const MIGRATION_PREF = "torbrowser.migration.version";
|
|
| 998 | + |
|
| 999 | + // If we decide to force updating users to pass through any version
|
|
| 1000 | + // following 12.0, we can remove this check, and check only whether
|
|
| 1001 | + // MIGRATION_PREF has a user value, like Mozilla does.
|
|
| 1002 | + if (isNewProfile) {
|
|
| 1003 | + // Do not migrate fresh profiles
|
|
| 1004 | + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION);
|
|
| 1005 | + return;
|
|
| 1006 | + } else if (isNewProfile === undefined) {
|
|
| 1007 | + // If this happens, check if upstream updated their function and do not
|
|
| 1008 | + // set this member anymore!
|
|
| 1009 | + console.error("upgradeTB: isNewProfile is undefined.");
|
|
| 1010 | + }
|
|
| 1011 | + |
|
| 1012 | + const currentVersion = Services.prefs.getIntPref(MIGRATION_PREF, 0);
|
|
| 1013 | + const removeLangpacks = async () => {
|
|
| 1014 | + for (const addon of await AddonManager.getAddonsByTypes(["locale"])) {
|
|
| 1015 | + await addon.uninstall();
|
|
| 1016 | + }
|
|
| 1017 | + };
|
|
| 1018 | + if (currentVersion < 1) {
|
|
| 1019 | + try {
|
|
| 1020 | + await removeLangpacks();
|
|
| 1021 | + } catch (err) {
|
|
| 1022 | + console.error("Could not remove langpacks", err);
|
|
| 1023 | + }
|
|
| 1024 | + }
|
|
| 1025 | + if (currentVersion < 2) {
|
|
| 1026 | + const prefToClear = [
|
|
| 1027 | + // tor-browser#41845: We were forcing these value by check the value of
|
|
| 1028 | + // automatic PBM. We decided not to change
|
|
| 1029 | + "browser.cache.disk.enable",
|
|
| 1030 | + "places.history.enabled",
|
|
| 1031 | + "security.nocertdb",
|
|
| 1032 | + "permissions.memory_only",
|
|
| 1033 | + // Old torbutton preferences not used anymore.
|
|
| 1034 | + "extensions.torbutton.loglevel",
|
|
| 1035 | + "extensions.torbutton.logmethod",
|
|
| 1036 | + "extensions.torbutton.pref_fixup_version",
|
|
| 1037 | + "extensions.torbutton.resize_new_windows",
|
|
| 1038 | + "extensions.torbutton.startup",
|
|
| 1039 | + "extensions.torlauncher.prompt_for_locale",
|
|
| 1040 | + "extensions.torlauncher.loglevel",
|
|
| 1041 | + "extensions.torlauncher.logmethod",
|
|
| 1042 | + "extensions.torlauncher.torrc_fixup_version",
|
|
| 1043 | + ];
|
|
| 1044 | + for (const pref of prefToClear) {
|
|
| 1045 | + if (Services.prefs.prefHasUserValue(pref)) {
|
|
| 1046 | + Services.prefs.clearUserPref(pref);
|
|
| 1047 | + }
|
|
| 1048 | + }
|
|
| 1049 | + }
|
|
| 1050 | + const dropAddons = async list => {
|
|
| 1051 | + for (const id of list) {
|
|
| 1052 | + try {
|
|
| 1053 | + const engine = await lazy.AddonManager.getAddonByID(id);
|
|
| 1054 | + await engine?.uninstall();
|
|
| 1055 | + } catch {}
|
|
| 1056 | + }
|
|
| 1057 | + };
|
|
| 1058 | + if (currentVersion < 3) {
|
|
| 1059 | + await dropAddons([
|
|
| 1060 | + "blockchair@search.mozilla.org",
|
|
| 1061 | + "blockchair-onion@search.mozilla.org",
|
|
| 1062 | + ]);
|
|
| 1063 | + }
|
|
| 1064 | + if (currentVersion < 4) {
|
|
| 1065 | + await dropAddons([
|
|
| 1066 | + "twitter@search.mozilla.org",
|
|
| 1067 | + "yahoo@search.mozilla.org",
|
|
| 1068 | + "youtube@search.mozilla.org",
|
|
| 1069 | + ]);
|
|
| 1070 | + }
|
|
| 1071 | + if (currentVersion < 5) {
|
|
| 1072 | + for (const pref of [
|
|
| 1073 | + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons",
|
|
| 1074 | + "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features",
|
|
| 1075 | + ]) {
|
|
| 1076 | + Services.prefs.clearUserPref(pref);
|
|
| 1077 | + }
|
|
| 1078 | + }
|
|
| 1079 | + if (currentVersion < 6) {
|
|
| 1080 | + Services.prefs.clearUserPref("torbrowser.settings.enabled");
|
|
| 1081 | + Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test");
|
|
| 1082 | + }
|
|
| 1083 | + if (currentVersion < 7) {
|
|
| 1084 | + Services.prefs.clearUserPref("torbrowser.post_update.url");
|
|
| 1085 | + }
|
|
| 1086 | + if (currentVersion < 8) {
|
|
| 1087 | + await dropAddons([
|
|
| 1088 | + "ddg@search.mozilla.org",
|
|
| 1089 | + "ddg-onion@search.mozilla.org",
|
|
| 1090 | + "google@search.mozilla.org",
|
|
| 1091 | + "startpage@search.mozilla.org",
|
|
| 1092 | + "startpage-onion@search.mozilla.org",
|
|
| 1093 | + "wikipedia@search.mozilla.org",
|
|
| 1094 | + ]);
|
|
| 1095 | + }
|
|
| 1096 | + |
|
| 1097 | + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION);
|
|
| 1098 | + },
|
|
| 903 | 1099 | }; |
| 1 | -// Copyright (c) 2022, The Tor Project, Inc.
|
|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 2 | 4 | |
| 3 | 5 | import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs";
|
| 4 | 6 | |
| ... | ... | @@ -6,7 +8,10 @@ const lazy = {}; |
| 6 | 8 | |
| 7 | 9 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 8 | 10 | JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
|
| 9 | - TorRequestWatch: "resource:///modules/TorRequestWatch.sys.mjs",
|
|
| 11 | + TorConnect: "resource://gre/modules/TorConnect.sys.mjs",
|
|
| 12 | + TorConnectTopics: "resource://gre/modules/TorConnect.sys.mjs",
|
|
| 13 | + TorRequestWatch:
|
|
| 14 | + "moz-src:///browser/components/onionservices/TorRequestWatch.sys.mjs",
|
|
| 10 | 15 | });
|
| 11 | 16 | |
| 12 | 17 | /* OnionAliasStore observer topics */
|
| ... | ... | @@ -84,12 +89,14 @@ class Channel { |
| 84 | 89 | };
|
| 85 | 90 | }
|
| 86 | 91 | |
| 92 | + #enabled;
|
|
| 93 | + |
|
| 87 | 94 | constructor(name, pathPrefix, jwk, scope, enabled) {
|
| 88 | 95 | this.name = name;
|
| 89 | 96 | this.pathPrefix = pathPrefix;
|
| 90 | 97 | this.jwk = jwk;
|
| 91 | 98 | this.scope = scope;
|
| 92 | - this._enabled = enabled;
|
|
| 99 | + this.#enabled = enabled;
|
|
| 93 | 100 | |
| 94 | 101 | this.mappings = [];
|
| 95 | 102 | this.currentTimestamp = 0;
|
| ... | ... | @@ -158,10 +165,10 @@ class Channel { |
| 158 | 165 | log.debug(
|
| 159 | 166 | `Downloaded and verified rules for ${this.name}, now uncompressing`
|
| 160 | 167 | );
|
| 161 | - this._makeMappings(JSON.parse(await gunzip(rulesGz)));
|
|
| 168 | + this.#makeMappings(JSON.parse(await gunzip(rulesGz)));
|
|
| 162 | 169 | }
|
| 163 | 170 | |
| 164 | - _makeMappings(rules) {
|
|
| 171 | + #makeMappings(rules) {
|
|
| 165 | 172 | const toTest = /^https?:\/\/[a-zA-Z0-9\.]{56}\.onion$/;
|
| 166 | 173 | const mappings = [];
|
| 167 | 174 | rules.rulesets.forEach(rule => {
|
| ... | ... | @@ -210,7 +217,7 @@ class Channel { |
| 210 | 217 | |
| 211 | 218 | async updateMappings(force) {
|
| 212 | 219 | force = force === undefined ? false : !!force;
|
| 213 | - if (!this._enabled && !force) {
|
|
| 220 | + if (!this.#enabled && !force) {
|
|
| 214 | 221 | return;
|
| 215 | 222 | }
|
| 216 | 223 | await this.updateLatestTimestamp();
|
| ... | ... | @@ -224,10 +231,10 @@ class Channel { |
| 224 | 231 | }
|
| 225 | 232 | |
| 226 | 233 | get enabled() {
|
| 227 | - return this._enabled;
|
|
| 234 | + return this.#enabled;
|
|
| 228 | 235 | }
|
| 229 | 236 | set enabled(enabled) {
|
| 230 | - this._enabled = enabled;
|
|
| 237 | + this.#enabled = enabled;
|
|
| 231 | 238 | if (!enabled) {
|
| 232 | 239 | this.mappings = [];
|
| 233 | 240 | this.currentTimestamp = 0;
|
| ... | ... | @@ -243,7 +250,7 @@ class Channel { |
| 243 | 250 | pathPrefix: this.pathPrefix,
|
| 244 | 251 | jwk: this.jwk,
|
| 245 | 252 | scope,
|
| 246 | - enabled: this._enabled,
|
|
| 253 | + enabled: this.#enabled,
|
|
| 247 | 254 | mappings: this.mappings,
|
| 248 | 255 | currentTimestamp: this.currentTimestamp,
|
| 249 | 256 | };
|
| ... | ... | @@ -277,37 +284,40 @@ class _OnionAliasStore { |
| 277 | 284 | return 86400 * 1000; // 1 day, like HTTPS-Everywhere
|
| 278 | 285 | }
|
| 279 | 286 | |
| 280 | - constructor() {
|
|
| 281 | - this._channels = new Map();
|
|
| 282 | - this._rulesetTimeout = null;
|
|
| 283 | - this._lastCheck = 0;
|
|
| 284 | - this._storage = null;
|
|
| 285 | - }
|
|
| 287 | + #channels = new Map();
|
|
| 288 | + #rulesetTimeout = null;
|
|
| 289 | + #lastCheck = 0;
|
|
| 290 | + #storage = null;
|
|
| 286 | 291 | |
| 287 | 292 | async init() {
|
| 288 | 293 | lazy.TorRequestWatch.start();
|
| 289 | - await this._loadSettings();
|
|
| 290 | - if (this.enabled) {
|
|
| 291 | - await this._startUpdates();
|
|
| 294 | + await this.#loadSettings();
|
|
| 295 | + if (this.enabled && !lazy.TorConnect.shouldShowTorConnect) {
|
|
| 296 | + await this.#startUpdates();
|
|
| 297 | + } else {
|
|
| 298 | + Services.obs.addObserver(this, lazy.TorConnectTopics.BootstrapComplete);
|
|
| 292 | 299 | }
|
| 293 | 300 | Services.prefs.addObserver(kPrefOnionAliasEnabled, this);
|
| 294 | 301 | }
|
| 295 | 302 | |
| 296 | 303 | uninit() {
|
| 297 | - this._clear();
|
|
| 298 | - if (this._rulesetTimeout) {
|
|
| 299 | - clearTimeout(this._rulesetTimeout);
|
|
| 304 | + this.#clear();
|
|
| 305 | + if (this.#rulesetTimeout) {
|
|
| 306 | + clearTimeout(this.#rulesetTimeout);
|
|
| 300 | 307 | }
|
| 301 | - this._rulesetTimeout = null;
|
|
| 308 | + this.#rulesetTimeout = null;
|
|
| 309 | + |
|
| 310 | + Services.obs.removeObserver(this, lazy.TorConnectTopics.BootstrapComplete);
|
|
| 302 | 311 | Services.prefs.removeObserver(kPrefOnionAliasEnabled, this);
|
| 312 | + |
|
| 303 | 313 | lazy.TorRequestWatch.stop();
|
| 304 | 314 | }
|
| 305 | 315 | |
| 306 | 316 | async getChannels() {
|
| 307 | - if (this._storage === null) {
|
|
| 308 | - await this._loadSettings();
|
|
| 317 | + if (this.#storage === null) {
|
|
| 318 | + await this.#loadSettings();
|
|
| 309 | 319 | }
|
| 310 | - return Array.from(this._channels.values(), ch => ch.toJSON());
|
|
| 320 | + return Array.from(this.#channels.values(), ch => ch.toJSON());
|
|
| 311 | 321 | }
|
| 312 | 322 | |
| 313 | 323 | async setChannel(chanData) {
|
| ... | ... | @@ -328,20 +338,20 @@ class _OnionAliasStore { |
| 328 | 338 | );
|
| 329 | 339 | // Call makeKey to make it throw if the key is invalid
|
| 330 | 340 | await ch.makeKey();
|
| 331 | - this._channels.set(name, ch);
|
|
| 332 | - this._applyMappings();
|
|
| 333 | - this._saveSettings();
|
|
| 334 | - setTimeout(this._notifyChanges.bind(this), 1);
|
|
| 341 | + this.#channels.set(name, ch);
|
|
| 342 | + this.#applyMappings();
|
|
| 343 | + this.#saveSettings();
|
|
| 344 | + setTimeout(this.#notifyChanges.bind(this), 1);
|
|
| 335 | 345 | return ch;
|
| 336 | 346 | }
|
| 337 | 347 | |
| 338 | 348 | enableChannel(name, enabled) {
|
| 339 | - const channel = this._channels.get(name);
|
|
| 349 | + const channel = this.#channels.get(name);
|
|
| 340 | 350 | if (channel !== null) {
|
| 341 | 351 | channel.enabled = enabled;
|
| 342 | - this._applyMappings();
|
|
| 343 | - this._saveSettings();
|
|
| 344 | - this._notifyChanges();
|
|
| 352 | + this.#applyMappings();
|
|
| 353 | + this.#saveSettings();
|
|
| 354 | + this.#notifyChanges();
|
|
| 345 | 355 | if (this.enabled && enabled && !channel.currentTimestamp) {
|
| 346 | 356 | this.updateChannel(name);
|
| 347 | 357 | }
|
| ... | ... | @@ -352,46 +362,46 @@ class _OnionAliasStore { |
| 352 | 362 | if (!this.enabled) {
|
| 353 | 363 | throw Error("Onion Aliases are disabled");
|
| 354 | 364 | }
|
| 355 | - const channel = this._channels.get(name);
|
|
| 365 | + const channel = this.#channels.get(name);
|
|
| 356 | 366 | if (channel === null) {
|
| 357 | 367 | throw Error("Channel not found");
|
| 358 | 368 | }
|
| 359 | 369 | await channel.updateMappings(true);
|
| 360 | - this._saveSettings();
|
|
| 361 | - this._applyMappings();
|
|
| 362 | - setTimeout(this._notifyChanges.bind(this), 1);
|
|
| 370 | + this.#saveSettings();
|
|
| 371 | + this.#applyMappings();
|
|
| 372 | + setTimeout(this.#notifyChanges.bind(this), 1);
|
|
| 363 | 373 | return channel;
|
| 364 | 374 | }
|
| 365 | 375 | |
| 366 | 376 | deleteChannel(name) {
|
| 367 | - if (this._channels.delete(name)) {
|
|
| 368 | - this._saveSettings();
|
|
| 369 | - this._applyMappings();
|
|
| 370 | - this._notifyChanges();
|
|
| 377 | + if (this.#channels.delete(name)) {
|
|
| 378 | + this.#saveSettings();
|
|
| 379 | + this.#applyMappings();
|
|
| 380 | + this.#notifyChanges();
|
|
| 371 | 381 | }
|
| 372 | 382 | }
|
| 373 | 383 | |
| 374 | - async _loadSettings() {
|
|
| 375 | - if (this._storage !== null) {
|
|
| 384 | + async #loadSettings() {
|
|
| 385 | + if (this.#storage !== null) {
|
|
| 376 | 386 | return;
|
| 377 | 387 | }
|
| 378 | - this._channels = new Map();
|
|
| 379 | - this._storage = new lazy.JSONFile({
|
|
| 388 | + this.#channels = new Map();
|
|
| 389 | + this.#storage = new lazy.JSONFile({
|
|
| 380 | 390 | path: PathUtils.join(
|
| 381 | 391 | Services.dirsvc.get("ProfD", Ci.nsIFile).path,
|
| 382 | 392 | "onion-aliases.json"
|
| 383 | 393 | ),
|
| 384 | - dataPostProcessor: this._settingsProcessor.bind(this),
|
|
| 394 | + dataPostProcessor: this.#settingsProcessor.bind(this),
|
|
| 385 | 395 | });
|
| 386 | - await this._storage.load();
|
|
| 387 | - log.debug("Loaded settings", this._storage.data, this._storage.path);
|
|
| 388 | - this._applyMappings();
|
|
| 389 | - this._notifyChanges();
|
|
| 396 | + await this.#storage.load();
|
|
| 397 | + log.debug("Loaded settings", this.#storage.data, this.#storage.path);
|
|
| 398 | + this.#applyMappings();
|
|
| 399 | + this.#notifyChanges();
|
|
| 390 | 400 | }
|
| 391 | 401 | |
| 392 | - _settingsProcessor(data) {
|
|
| 402 | + #settingsProcessor(data) {
|
|
| 393 | 403 | if ("lastCheck" in data) {
|
| 394 | - this._lastCheck = data.lastCheck;
|
|
| 404 | + this.#lastCheck = data.lastCheck;
|
|
| 395 | 405 | } else {
|
| 396 | 406 | data.lastCheck = 0;
|
| 397 | 407 | }
|
| ... | ... | @@ -410,56 +420,56 @@ class _OnionAliasStore { |
| 410 | 420 | }
|
| 411 | 421 | return true;
|
| 412 | 422 | });
|
| 413 | - this._channels = channels;
|
|
| 423 | + this.#channels = channels;
|
|
| 414 | 424 | return data;
|
| 415 | 425 | }
|
| 416 | 426 | |
| 417 | - _saveSettings() {
|
|
| 418 | - if (this._storage === null) {
|
|
| 427 | + #saveSettings() {
|
|
| 428 | + if (this.#storage === null) {
|
|
| 419 | 429 | throw Error("Settings have not been loaded");
|
| 420 | 430 | }
|
| 421 | - this._storage.data.lastCheck = this._lastCheck;
|
|
| 422 | - this._storage.data.channels = Array.from(this._channels.values(), ch =>
|
|
| 431 | + this.#storage.data.lastCheck = this.#lastCheck;
|
|
| 432 | + this.#storage.data.channels = Array.from(this.#channels.values(), ch =>
|
|
| 423 | 433 | ch.toJSON()
|
| 424 | 434 | );
|
| 425 | - this._storage.saveSoon();
|
|
| 435 | + this.#storage.saveSoon();
|
|
| 426 | 436 | }
|
| 427 | 437 | |
| 428 | - _addMapping(shortOnionHost, longOnionHost) {
|
|
| 438 | + #addMapping(shortOnionHost, longOnionHost) {
|
|
| 429 | 439 | const service = Cc["@torproject.org/onion-alias-service;1"].getService(
|
| 430 | 440 | Ci.IOnionAliasService
|
| 431 | 441 | );
|
| 432 | 442 | service.addOnionAlias(shortOnionHost, longOnionHost);
|
| 433 | 443 | }
|
| 434 | 444 | |
| 435 | - _clear() {
|
|
| 445 | + #clear() {
|
|
| 436 | 446 | const service = Cc["@torproject.org/onion-alias-service;1"].getService(
|
| 437 | 447 | Ci.IOnionAliasService
|
| 438 | 448 | );
|
| 439 | 449 | service.clearOnionAliases();
|
| 440 | 450 | }
|
| 441 | 451 | |
| 442 | - _applyMappings() {
|
|
| 443 | - this._clear();
|
|
| 444 | - for (const ch of this._channels.values()) {
|
|
| 452 | + #applyMappings() {
|
|
| 453 | + this.#clear();
|
|
| 454 | + for (const ch of this.#channels.values()) {
|
|
| 445 | 455 | if (!ch.enabled) {
|
| 446 | 456 | continue;
|
| 447 | 457 | }
|
| 448 | 458 | for (const [short, long] of ch.mappings) {
|
| 449 | - this._addMapping(short, long);
|
|
| 459 | + this.#addMapping(short, long);
|
|
| 450 | 460 | }
|
| 451 | 461 | }
|
| 452 | 462 | }
|
| 453 | 463 | |
| 454 | - async _periodicRulesetCheck() {
|
|
| 464 | + async #periodicRulesetCheck() {
|
|
| 455 | 465 | if (!this.enabled) {
|
| 456 | 466 | log.debug("Onion Aliases are disabled, not updating rulesets.");
|
| 457 | 467 | return;
|
| 458 | 468 | }
|
| 459 | 469 | log.debug("Begin scheduled ruleset update");
|
| 460 | - this._lastCheck = Date.now();
|
|
| 470 | + this.#lastCheck = Date.now();
|
|
| 461 | 471 | let anyUpdated = false;
|
| 462 | - for (const ch of this._channels.values()) {
|
|
| 472 | + for (const ch of this.#channels.values()) {
|
|
| 463 | 473 | if (!ch.enabled) {
|
| 464 | 474 | log.debug(`Not updating ${ch.name} because not enabled`);
|
| 465 | 475 | continue;
|
| ... | ... | @@ -473,22 +483,22 @@ class _OnionAliasStore { |
| 473 | 483 | }
|
| 474 | 484 | }
|
| 475 | 485 | if (anyUpdated) {
|
| 476 | - this._saveSettings();
|
|
| 477 | - this._applyMappings();
|
|
| 478 | - this._notifyChanges();
|
|
| 486 | + this.#saveSettings();
|
|
| 487 | + this.#applyMappings();
|
|
| 488 | + this.#notifyChanges();
|
|
| 479 | 489 | } else {
|
| 480 | 490 | log.debug("No channel has been updated, avoid saving");
|
| 481 | 491 | }
|
| 482 | - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL);
|
|
| 492 | + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL);
|
|
| 483 | 493 | }
|
| 484 | 494 | |
| 485 | - async _startUpdates() {
|
|
| 486 | - // This is a "private" function, so we expect the callers to verify wheter
|
|
| 495 | + async #startUpdates() {
|
|
| 496 | + // This is a private function, so we expect the callers to verify whether
|
|
| 487 | 497 | // onion aliases are enabled.
|
| 488 | 498 | // Callees will also do, so we avoid an additional check here.
|
| 489 | - const dt = Date.now() - this._lastCheck;
|
|
| 499 | + const dt = Date.now() - this.#lastCheck;
|
|
| 490 | 500 | let force = false;
|
| 491 | - for (const ch of this._channels.values()) {
|
|
| 501 | + for (const ch of this.#channels.values()) {
|
|
| 492 | 502 | if (ch.enabled && !ch.currentTimestamp) {
|
| 493 | 503 | // Edited while being offline or some other error happened
|
| 494 | 504 | force = true;
|
| ... | ... | @@ -499,34 +509,34 @@ class _OnionAliasStore { |
| 499 | 509 | log.debug(
|
| 500 | 510 | `Mappings are stale (${dt}), or force check requested (${force}), checking them immediately`
|
| 501 | 511 | );
|
| 502 | - await this._periodicRulesetCheck();
|
|
| 512 | + await this.#periodicRulesetCheck();
|
|
| 503 | 513 | } else {
|
| 504 | - this._scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt);
|
|
| 514 | + this.#scheduleCheck(_OnionAliasStore.RULESET_CHECK_INTERVAL - dt);
|
|
| 505 | 515 | }
|
| 506 | 516 | }
|
| 507 | 517 | |
| 508 | - _scheduleCheck(dt) {
|
|
| 509 | - if (this._rulesetTimeout) {
|
|
| 518 | + #scheduleCheck(dt) {
|
|
| 519 | + if (this.#rulesetTimeout) {
|
|
| 510 | 520 | log.warn("The previous update timeout was not null");
|
| 511 | - clearTimeout(this._rulesetTimeout);
|
|
| 521 | + clearTimeout(this.#rulesetTimeout);
|
|
| 512 | 522 | }
|
| 513 | 523 | if (!this.enabled) {
|
| 514 | 524 | log.warn(
|
| 515 | 525 | "Ignoring the scheduling of a new check because the Onion Alias feature is currently disabled."
|
| 516 | 526 | );
|
| 517 | - this._rulesetTimeout = null;
|
|
| 527 | + this.#rulesetTimeout = null;
|
|
| 518 | 528 | return;
|
| 519 | 529 | }
|
| 520 | 530 | log.debug(`Scheduling ruleset update in ${dt}`);
|
| 521 | - this._rulesetTimeout = setTimeout(() => {
|
|
| 522 | - this._rulesetTimeout = null;
|
|
| 523 | - this._periodicRulesetCheck();
|
|
| 531 | + this.#rulesetTimeout = setTimeout(() => {
|
|
| 532 | + this.#rulesetTimeout = null;
|
|
| 533 | + this.#periodicRulesetCheck();
|
|
| 524 | 534 | }, dt);
|
| 525 | 535 | }
|
| 526 | 536 | |
| 527 | - _notifyChanges() {
|
|
| 537 | + #notifyChanges() {
|
|
| 528 | 538 | Services.obs.notifyObservers(
|
| 529 | - Array.from(this._channels.values(), ch => ch.toJSON()),
|
|
| 539 | + Array.from(this.#channels.values(), ch => ch.toJSON()),
|
|
| 530 | 540 | OnionAliasStoreTopics.ChannelsChanged
|
| 531 | 541 | );
|
| 532 | 542 | }
|
| ... | ... | @@ -538,11 +548,16 @@ class _OnionAliasStore { |
| 538 | 548 | observe(aSubject, aTopic) {
|
| 539 | 549 | if (aTopic === "nsPref:changed") {
|
| 540 | 550 | if (this.enabled) {
|
| 541 | - this._startUpdates();
|
|
| 542 | - } else if (this._rulesetTimeout) {
|
|
| 543 | - clearTimeout(this._rulesetTimeout);
|
|
| 544 | - this._rulesetTimeout = null;
|
|
| 551 | + this.#startUpdates();
|
|
| 552 | + } else if (this.#rulesetTimeout) {
|
|
| 553 | + clearTimeout(this.#rulesetTimeout);
|
|
| 554 | + this.#rulesetTimeout = null;
|
|
| 545 | 555 | }
|
| 556 | + } else if (
|
|
| 557 | + aTopic === lazy.TorConnectTopics.BootstrapComplete &&
|
|
| 558 | + this.enabled
|
|
| 559 | + ) {
|
|
| 560 | + this.#startUpdates();
|
|
| 546 | 561 | }
|
| 547 | 562 | }
|
| 548 | 563 | }
|
| 1 | 1 | JAR_MANIFESTS += ["jar.mn"]
|
| 2 | 2 | |
| 3 | 3 | EXTRA_JS_MODULES += [
|
| 4 | - "OnionAliasStore.sys.mjs",
|
|
| 5 | 4 | "OnionLocationChild.sys.mjs",
|
| 6 | 5 | "OnionLocationParent.sys.mjs",
|
| 6 | +]
|
|
| 7 | + |
|
| 8 | +MOZ_SRC_FILES += [
|
|
| 9 | + "OnionAliasStore.sys.mjs",
|
|
| 7 | 10 | "TorRequestWatch.sys.mjs",
|
| 8 | 11 | ] |
| 1 | -// Copyright (c) 2022, The Tor Project, Inc.
|
|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 2 | 4 | |
| 3 | 5 | import {
|
| 4 | 6 | OnionAliasStore,
|
| 5 | 7 | OnionAliasStoreTopics,
|
| 6 | -} from "resource:///modules/OnionAliasStore.sys.mjs";
|
|
| 8 | +} from "moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs";
|
|
| 7 | 9 | |
| 8 | 10 | const kShowWarningPref = "torbrowser.rulesets.show_warning";
|
| 9 | 11 | |
| ... | ... | @@ -56,9 +58,10 @@ export class RulesetsParent extends JSWindowActorParent { |
| 56 | 58 | return {
|
| 57 | 59 | showWarning: Services.prefs.getBoolPref(kShowWarningPref, true),
|
| 58 | 60 | };
|
| 59 | - case "rulesets:set-channel":
|
|
| 61 | + case "rulesets:set-channel": {
|
|
| 60 | 62 | const ch = await OnionAliasStore.setChannel(message.data);
|
| 61 | 63 | return ch;
|
| 64 | + }
|
|
| 62 | 65 | case "rulesets:update-channel":
|
| 63 | 66 | // We need to catch any error in this way, because in case of an
|
| 64 | 67 | // exception, RPMSendQuery does not return on the other side
|
| 1 | +/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
| 2 | + * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
| 3 | + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
| 4 | + |
|
| 5 | +const lazy = {};
|
|
| 6 | + |
|
| 7 | +ChromeUtils.defineESModuleGetters(lazy, {
|
|
| 8 | + AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
|
|
| 9 | + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
|
| 10 | + setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
|
| 11 | +});
|
|
| 12 | + |
|
| 13 | +/**
|
|
| 14 | + * Empty clipboard content from private windows on exit.
|
|
| 15 | + *
|
|
| 16 | + * See tor-browser#42154.
|
|
| 17 | + */
|
|
| 18 | +export const ClipboardPrivacy = {
|
|
| 19 | + _lastClipboardHash: null,
|
|
| 20 | + _globalActivation: false,
|
|
| 21 | + _isPrivateClipboard: false,
|
|
| 22 | + _hasher: null,
|
|
| 23 | + _shuttingDown: false,
|
|
| 24 | + _log: null,
|
|
| 25 | + |
|
| 26 | + _createTransferable() {
|
|
| 27 | + const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
|
| 28 | + Ci.nsITransferable
|
|
| 29 | + );
|
|
| 30 | + trans.init(null);
|
|
| 31 | + return trans;
|
|
| 32 | + },
|
|
| 33 | + _computeClipboardHash() {
|
|
| 34 | + const flavors = ["text/x-moz-url", "text/plain"];
|
|
| 35 | + if (
|
|
| 36 | + !Services.clipboard.hasDataMatchingFlavors(
|
|
| 37 | + flavors,
|
|
| 38 | + Ci.nsIClipboard.kGlobalClipboard
|
|
| 39 | + )
|
|
| 40 | + ) {
|
|
| 41 | + return null;
|
|
| 42 | + }
|
|
| 43 | + const trans = this._createTransferable();
|
|
| 44 | + flavors.forEach(trans.addDataFlavor);
|
|
| 45 | + try {
|
|
| 46 | + Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard);
|
|
| 47 | + const clipboardContent = {};
|
|
| 48 | + trans.getAnyTransferData({}, clipboardContent);
|
|
| 49 | + const { data } = clipboardContent.value.QueryInterface(
|
|
| 50 | + Ci.nsISupportsString
|
|
| 51 | + );
|
|
| 52 | + const bytes = new TextEncoder().encode(data);
|
|
| 53 | + const hasher = (this._hasher ||= Cc[
|
|
| 54 | + "@mozilla.org/security/hash;1"
|
|
| 55 | + ].createInstance(Ci.nsICryptoHash));
|
|
| 56 | + hasher.init(hasher.SHA256);
|
|
| 57 | + hasher.update(bytes, bytes.length);
|
|
| 58 | + return hasher.finish(true);
|
|
| 59 | + } catch (e) {}
|
|
| 60 | + return null;
|
|
| 61 | + },
|
|
| 62 | + |
|
| 63 | + init() {
|
|
| 64 | + this._log = console.createInstance({
|
|
| 65 | + prefix: "ClipboardPrivacy",
|
|
| 66 | + });
|
|
| 67 | + this._lastClipboardHash = this._computeClipboardHash();
|
|
| 68 | + |
|
| 69 | + // Here we track changes in active window / application,
|
|
| 70 | + // by filtering focus events and window closures.
|
|
| 71 | + const handleActivation = (win, activation) => {
|
|
| 72 | + if (activation) {
|
|
| 73 | + if (!this._globalActivation) {
|
|
| 74 | + // focus changed within this window, bail out.
|
|
| 75 | + return;
|
|
| 76 | + }
|
|
| 77 | + this._globalActivation = false;
|
|
| 78 | + } else if (!Services.focus.activeWindow) {
|
|
| 79 | + // focus is leaving this window:
|
|
| 80 | + // let's track whether it remains within the browser.
|
|
| 81 | + lazy.setTimeout(() => {
|
|
| 82 | + this._globalActivation = !Services.focus.activeWindow;
|
|
| 83 | + }, 100);
|
|
| 84 | + }
|
|
| 85 | + |
|
| 86 | + const checkClipboardContent = () => {
|
|
| 87 | + const clipboardHash = this._computeClipboardHash();
|
|
| 88 | + if (clipboardHash !== this._lastClipboardHash) {
|
|
| 89 | + this._isPrivateClipboard =
|
|
| 90 | + !activation &&
|
|
| 91 | + (lazy.PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
|
| 92 | + lazy.PrivateBrowsingUtils.isWindowPrivate(win));
|
|
| 93 | + this._lastClipboardHash = clipboardHash;
|
|
| 94 | + this._log.debug(
|
|
| 95 | + `Clipboard changed: private ${this._isPrivateClipboard}, hash ${clipboardHash}.`
|
|
| 96 | + );
|
|
| 97 | + }
|
|
| 98 | + };
|
|
| 99 | + |
|
| 100 | + if (win.closed) {
|
|
| 101 | + checkClipboardContent();
|
|
| 102 | + } else {
|
|
| 103 | + // defer clipboard access on DOM events to work-around tor-browser#42306
|
|
| 104 | + lazy.setTimeout(checkClipboardContent, 0);
|
|
| 105 | + }
|
|
| 106 | + };
|
|
| 107 | + const focusListener = e =>
|
|
| 108 | + e.isTrusted && handleActivation(e.currentTarget, e.type === "focusin");
|
|
| 109 | + const initWindow = win => {
|
|
| 110 | + for (const e of ["focusin", "focusout"]) {
|
|
| 111 | + win.addEventListener(e, focusListener);
|
|
| 112 | + }
|
|
| 113 | + };
|
|
| 114 | + for (const w of Services.ww.getWindowEnumerator()) {
|
|
| 115 | + initWindow(w);
|
|
| 116 | + }
|
|
| 117 | + Services.ww.registerNotification((win, event) => {
|
|
| 118 | + switch (event) {
|
|
| 119 | + case "domwindowopened":
|
|
| 120 | + initWindow(win);
|
|
| 121 | + break;
|
|
| 122 | + case "domwindowclosed":
|
|
| 123 | + handleActivation(win, false);
|
|
| 124 | + if (
|
|
| 125 | + this._isPrivateClipboard &&
|
|
| 126 | + lazy.PrivateBrowsingUtils.isWindowPrivate(win) &&
|
|
| 127 | + (this._shuttingDown ||
|
|
| 128 | + !Array.from(Services.ww.getWindowEnumerator()).find(
|
|
| 129 | + w =>
|
|
| 130 | + lazy.PrivateBrowsingUtils.isWindowPrivate(w) &&
|
|
| 131 | + // We need to filter out the HIDDEN WebExtensions window,
|
|
| 132 | + // which might be private as well but is not UI-relevant.
|
|
| 133 | + !w.location.href.startsWith("chrome://extensions/")
|
|
| 134 | + ))
|
|
| 135 | + ) {
|
|
| 136 | + // no more private windows, empty private content if needed
|
|
| 137 | + this.emptyPrivate();
|
|
| 138 | + }
|
|
| 139 | + }
|
|
| 140 | + });
|
|
| 141 | + |
|
| 142 | + lazy.AsyncShutdown.quitApplicationGranted.addBlocker(
|
|
| 143 | + "ClipboardPrivacy: removing private data",
|
|
| 144 | + () => {
|
|
| 145 | + this._shuttingDown = true;
|
|
| 146 | + this.emptyPrivate();
|
|
| 147 | + }
|
|
| 148 | + );
|
|
| 149 | + },
|
|
| 150 | + emptyPrivate() {
|
|
| 151 | + if (
|
|
| 152 | + this._isPrivateClipboard &&
|
|
| 153 | + !Services.prefs.getBoolPref(
|
|
| 154 | + "browser.privatebrowsing.preserveClipboard",
|
|
| 155 | + false
|
|
| 156 | + ) &&
|
|
| 157 | + this._lastClipboardHash === this._computeClipboardHash()
|
|
| 158 | + ) {
|
|
| 159 | + // nsIClipboard.emptyClipboard() does nothing in Wayland:
|
|
| 160 | + // we'll set an empty string as a work-around.
|
|
| 161 | + const trans = this._createTransferable();
|
|
| 162 | + const flavor = "text/plain";
|
|
| 163 | + trans.addDataFlavor(flavor);
|
|
| 164 | + const emptyString = Cc["@mozilla.org/supports-string;1"].createInstance(
|
|
| 165 | + Ci.nsISupportsString
|
|
| 166 | + );
|
|
| 167 | + emptyString.data = "";
|
|
| 168 | + trans.setTransferData(flavor, emptyString);
|
|
| 169 | + const { clipboard } = Services,
|
|
| 170 | + { kGlobalClipboard } = clipboard;
|
|
| 171 | + clipboard.setData(trans, null, kGlobalClipboard);
|
|
| 172 | + clipboard.emptyClipboard(kGlobalClipboard);
|
|
| 173 | + this._lastClipboardHash = null;
|
|
| 174 | + this._isPrivateClipboard = false;
|
|
| 175 | + this._log.info("Private clipboard emptied.");
|
|
| 176 | + }
|
|
| 177 | + },
|
|
| 178 | +}; |
| ... | ... | @@ -136,12 +136,10 @@ EXTRA_JS_MODULES += [ |
| 136 | 136 | "PopupBlockerObserver.sys.mjs",
|
| 137 | 137 | "ProcessHangMonitor.sys.mjs",
|
| 138 | 138 | "Sanitizer.sys.mjs",
|
| 139 | - "SecurityLevelRestartNotification.sys.mjs",
|
|
| 140 | 139 | "SelectionChangedMenulist.sys.mjs",
|
| 141 | 140 | "SharingUtils.sys.mjs",
|
| 142 | 141 | "SiteDataManager.sys.mjs",
|
| 143 | 142 | "SitePermissions.sys.mjs",
|
| 144 | - "TorSettingsNotification.sys.mjs",
|
|
| 145 | 143 | "TorUIUtils.sys.mjs",
|
| 146 | 144 | "TransientPrefs.sys.mjs",
|
| 147 | 145 | "URILoadingHelper.sys.mjs",
|
| ... | ... | @@ -151,6 +149,9 @@ EXTRA_JS_MODULES += [ |
| 151 | 149 | |
| 152 | 150 | MOZ_SRC_FILES += [
|
| 153 | 151 | "ContextId.sys.mjs",
|
| 152 | + "ClipboardPrivacy.sys.mjs",
|
|
| 153 | + "SecurityLevelRestartNotification.sys.mjs",
|
|
| 154 | + "TorSettingsNotification.sys.mjs",
|
|
| 154 | 155 | ]
|
| 155 | 156 | |
| 156 | 157 | if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
|
| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | const lazy = {};
|
| 6 | 6 | |
| 7 | 7 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 8 | - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs",
|
|
| 8 | + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs",
|
|
| 9 | 9 | });
|
| 10 | 10 | |
| 11 | 11 | // This component is used for handling dragover and drop of urls.
|
| ... | ... | @@ -12,7 +12,7 @@ const lazy = {}; |
| 12 | 12 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 13 | 13 | Bookmarks: "resource://gre/modules/Bookmarks.sys.mjs",
|
| 14 | 14 | History: "resource://gre/modules/History.sys.mjs",
|
| 15 | - OpaqueDrag: "resource://gre/modules/DragDropFilter.sys.mjs",
|
|
| 15 | + OpaqueDrag: "moz-src:///toolkit/modules/DragDropFilter.sys.mjs",
|
|
| 16 | 16 | PlacesSyncUtils: "resource://gre/modules/PlacesSyncUtils.sys.mjs",
|
| 17 | 17 | Sqlite: "resource://gre/modules/Sqlite.sys.mjs",
|
| 18 | 18 | });
|
| 1 | 1 | category profile-after-change TorStartupService @torproject.org/tor-startup-service;1
|
| 2 | +category browser-first-window-ready resource://gre/modules/TorProviderBuilder.sys.mjs TorProviderBuilder.firstWindowLoaded |
| ... | ... | @@ -164,7 +164,6 @@ EXTRA_JS_MODULES += [ |
| 164 | 164 | "DateTimePickerPanel.sys.mjs",
|
| 165 | 165 | "DeferredTask.sys.mjs",
|
| 166 | 166 | "DomainFrontedRequests.sys.mjs",
|
| 167 | - "DragDropFilter.sys.mjs",
|
|
| 168 | 167 | "E10SUtils.sys.mjs",
|
| 169 | 168 | "EventEmitter.sys.mjs",
|
| 170 | 169 | "FileUtils.sys.mjs",
|
| ... | ... | @@ -220,6 +219,10 @@ EXTRA_JS_MODULES += [ |
| 220 | 219 | "WebChannel.sys.mjs",
|
| 221 | 220 | ]
|
| 222 | 221 | |
| 222 | +MOZ_SRC_FILES += [
|
|
| 223 | + "DragDropFilter.sys.mjs",
|
|
| 224 | +]
|
|
| 225 | + |
|
| 223 | 226 | if CONFIG["MOZ_ASAN_REPORTER"]:
|
| 224 | 227 | EXTRA_JS_MODULES += [
|
| 225 | 228 | "AsanReporter.sys.mjs",
|