Loading browser/app/profile/000-tor-browser.js +2 −0 Original line number Diff line number Diff line Loading @@ -128,3 +128,5 @@ pref("extensions.torlauncher.bridgedb_reflector", "https://1723079976.rsc.cdn77. pref("extensions.torlauncher.moat_service", "https://bridges.torproject.org/moat"); // Log levels pref("browser.tor_provider.log_level", "Warn"); pref("browser.tor_provider.cp_log_level", "Warn"); browser/components/BrowserGlue.sys.mjs +3 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ ChromeUtils.defineESModuleGetters(lazy, { TabCrashHandler: "resource:///modules/ContentCrashHandlers.sys.mjs", TabUnloader: "resource:///modules/TabUnloader.sys.mjs", TelemetryUtils: "resource://gre/modules/TelemetryUtils.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", UIState: "resource://services-sync/UIState.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", WebChannel: "resource://gre/modules/WebChannel.sys.mjs", Loading Loading @@ -1972,6 +1973,8 @@ BrowserGlue.prototype = { lazy.DoHController.init(); lazy.TorProviderBuilder.firstWindowLoaded(); ClipboardPrivacy.startup(); this._firstWindowTelemetry(aWindow); Loading browser/installer/package-manifest.in +1 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,7 @@ @RESPATH@/browser/chrome/browser.manifest @RESPATH@/chrome/pdfjs.manifest @RESPATH@/chrome/pdfjs/* @RESPATH@/components/tor-launcher.manifest @RESPATH@/chrome/torbutton.manifest @RESPATH@/chrome/torbutton/* @RESPATH@/chrome/toolkit@JAREXT@ Loading toolkit/components/moz.build +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ DIRS += [ "thumbnails", "timermanager", "tooltiptext", "tor-launcher", "typeaheadfind", "utils", "url-classifier", Loading toolkit/components/tor-launcher/TorBootstrapRequest.sys.mjs 0 → 100644 +147 −0 Original line number Diff line number Diff line import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); const log = console.createInstance({ maxLogLevel: "Info", prefix: "TorBootstrapRequest", }); /** * This class encapsulates the observer register/unregister logic to provide an * XMLHttpRequest-like API to bootstrap tor. * TODO: Remove this class, and move its logic inside the TorProvider. */ export class TorBootstrapRequest { // number of ms to wait before we abandon the bootstrap attempt // a value of 0 implies we never wait timeout = 0; // callbacks for bootstrap process status updates onbootstrapstatus = (_progress, _status) => {}; onbootstrapcomplete = () => {}; onbootstraperror = _error => {}; // internal resolve() method for bootstrap #bootstrapPromiseResolve = null; #bootstrapPromise = null; #timeoutID = null; observe(subject, topic) { const obj = subject?.wrappedJSObject; switch (topic) { case lazy.TorProviderTopics.BootstrapStatus: { const progress = obj.PROGRESS; if (this.onbootstrapstatus) { const status = obj.TAG; this.onbootstrapstatus(progress, status); } if (progress === 100) { if (this.onbootstrapcomplete) { this.onbootstrapcomplete(); } this.#bootstrapPromiseResolve(true); clearTimeout(this.#timeoutID); this.#timeoutID = null; } break; } case lazy.TorProviderTopics.BootstrapError: { log.info("TorBootstrapRequest: observerd TorBootstrapError", obj); const error = new Error(obj.summary); Object.assign(error, obj); this.#stop(error); break; } } } // resolves 'true' if bootstrap succeeds, false otherwise bootstrap() { if (this.#bootstrapPromise) { return this.#bootstrapPromise; } this.#bootstrapPromise = new Promise(resolve => { this.#bootstrapPromiseResolve = resolve; // register ourselves to listen for bootstrap events Services.obs.addObserver(this, lazy.TorProviderTopics.BootstrapStatus); Services.obs.addObserver(this, lazy.TorProviderTopics.BootstrapError); // optionally cancel bootstrap after a given timeout if (this.timeout > 0) { this.#timeoutID = setTimeout(() => { this.#timeoutID = null; this.#stop( new Error( `Bootstrap attempt abandoned after waiting ${this.timeout} ms` ) ); }, this.timeout); } // Wait for bootstrapping to begin and maybe handle error. // Notice that we do not resolve the promise here in case of success, but // we do it from the BootstrapStatus observer. // NOTE: After TorProviderBuilder.build resolves, TorProvider.init will // have completed. In particular, assuming no errors, the TorSettings will // have been initialised and passed on to the provider via // TorProvider.writeSettings. Therefore we should be safe to immediately // call `connect` using the latest user settings. lazy.TorProviderBuilder.build() .then(provider => provider.connect()) .catch(err => { this.#stop(err); }); }).finally(() => { // and remove ourselves once bootstrap is resolved Services.obs.removeObserver(this, lazy.TorProviderTopics.BootstrapStatus); Services.obs.removeObserver(this, lazy.TorProviderTopics.BootstrapError); this.#bootstrapPromise = null; }); return this.#bootstrapPromise; } async cancel() { await this.#stop(); } // Internal implementation. Do not use directly, but call cancel, instead. async #stop(error) { // first stop our bootstrap timeout before handling the error if (this.#timeoutID !== null) { clearTimeout(this.#timeoutID); this.#timeoutID = null; } let provider; try { provider = await lazy.TorProviderBuilder.build(); } catch { // This was probably the error that lead to stop in the first place. // No need to continue propagating it. } try { await provider?.stopBootstrap(); } catch (e) { console.error("Failed to stop the bootstrap.", e); if (!error) { error = e; } } if (this.onbootstraperror && error) { this.onbootstraperror(error); } this.#bootstrapPromiseResolve(false); } } Loading
browser/app/profile/000-tor-browser.js +2 −0 Original line number Diff line number Diff line Loading @@ -128,3 +128,5 @@ pref("extensions.torlauncher.bridgedb_reflector", "https://1723079976.rsc.cdn77. pref("extensions.torlauncher.moat_service", "https://bridges.torproject.org/moat"); // Log levels pref("browser.tor_provider.log_level", "Warn"); pref("browser.tor_provider.cp_log_level", "Warn");
browser/components/BrowserGlue.sys.mjs +3 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ ChromeUtils.defineESModuleGetters(lazy, { TabCrashHandler: "resource:///modules/ContentCrashHandlers.sys.mjs", TabUnloader: "resource:///modules/TabUnloader.sys.mjs", TelemetryUtils: "resource://gre/modules/TelemetryUtils.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", UIState: "resource://services-sync/UIState.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", WebChannel: "resource://gre/modules/WebChannel.sys.mjs", Loading Loading @@ -1972,6 +1973,8 @@ BrowserGlue.prototype = { lazy.DoHController.init(); lazy.TorProviderBuilder.firstWindowLoaded(); ClipboardPrivacy.startup(); this._firstWindowTelemetry(aWindow); Loading
browser/installer/package-manifest.in +1 −0 Original line number Diff line number Diff line Loading @@ -213,6 +213,7 @@ @RESPATH@/browser/chrome/browser.manifest @RESPATH@/chrome/pdfjs.manifest @RESPATH@/chrome/pdfjs/* @RESPATH@/components/tor-launcher.manifest @RESPATH@/chrome/torbutton.manifest @RESPATH@/chrome/torbutton/* @RESPATH@/chrome/toolkit@JAREXT@ Loading
toolkit/components/moz.build +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ DIRS += [ "thumbnails", "timermanager", "tooltiptext", "tor-launcher", "typeaheadfind", "utils", "url-classifier", Loading
toolkit/components/tor-launcher/TorBootstrapRequest.sys.mjs 0 → 100644 +147 −0 Original line number Diff line number Diff line import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); const log = console.createInstance({ maxLogLevel: "Info", prefix: "TorBootstrapRequest", }); /** * This class encapsulates the observer register/unregister logic to provide an * XMLHttpRequest-like API to bootstrap tor. * TODO: Remove this class, and move its logic inside the TorProvider. */ export class TorBootstrapRequest { // number of ms to wait before we abandon the bootstrap attempt // a value of 0 implies we never wait timeout = 0; // callbacks for bootstrap process status updates onbootstrapstatus = (_progress, _status) => {}; onbootstrapcomplete = () => {}; onbootstraperror = _error => {}; // internal resolve() method for bootstrap #bootstrapPromiseResolve = null; #bootstrapPromise = null; #timeoutID = null; observe(subject, topic) { const obj = subject?.wrappedJSObject; switch (topic) { case lazy.TorProviderTopics.BootstrapStatus: { const progress = obj.PROGRESS; if (this.onbootstrapstatus) { const status = obj.TAG; this.onbootstrapstatus(progress, status); } if (progress === 100) { if (this.onbootstrapcomplete) { this.onbootstrapcomplete(); } this.#bootstrapPromiseResolve(true); clearTimeout(this.#timeoutID); this.#timeoutID = null; } break; } case lazy.TorProviderTopics.BootstrapError: { log.info("TorBootstrapRequest: observerd TorBootstrapError", obj); const error = new Error(obj.summary); Object.assign(error, obj); this.#stop(error); break; } } } // resolves 'true' if bootstrap succeeds, false otherwise bootstrap() { if (this.#bootstrapPromise) { return this.#bootstrapPromise; } this.#bootstrapPromise = new Promise(resolve => { this.#bootstrapPromiseResolve = resolve; // register ourselves to listen for bootstrap events Services.obs.addObserver(this, lazy.TorProviderTopics.BootstrapStatus); Services.obs.addObserver(this, lazy.TorProviderTopics.BootstrapError); // optionally cancel bootstrap after a given timeout if (this.timeout > 0) { this.#timeoutID = setTimeout(() => { this.#timeoutID = null; this.#stop( new Error( `Bootstrap attempt abandoned after waiting ${this.timeout} ms` ) ); }, this.timeout); } // Wait for bootstrapping to begin and maybe handle error. // Notice that we do not resolve the promise here in case of success, but // we do it from the BootstrapStatus observer. // NOTE: After TorProviderBuilder.build resolves, TorProvider.init will // have completed. In particular, assuming no errors, the TorSettings will // have been initialised and passed on to the provider via // TorProvider.writeSettings. Therefore we should be safe to immediately // call `connect` using the latest user settings. lazy.TorProviderBuilder.build() .then(provider => provider.connect()) .catch(err => { this.#stop(err); }); }).finally(() => { // and remove ourselves once bootstrap is resolved Services.obs.removeObserver(this, lazy.TorProviderTopics.BootstrapStatus); Services.obs.removeObserver(this, lazy.TorProviderTopics.BootstrapError); this.#bootstrapPromise = null; }); return this.#bootstrapPromise; } async cancel() { await this.#stop(); } // Internal implementation. Do not use directly, but call cancel, instead. async #stop(error) { // first stop our bootstrap timeout before handling the error if (this.#timeoutID !== null) { clearTimeout(this.#timeoutID); this.#timeoutID = null; } let provider; try { provider = await lazy.TorProviderBuilder.build(); } catch { // This was probably the error that lead to stop in the first place. // No need to continue propagating it. } try { await provider?.stopBootstrap(); } catch (e) { console.error("Failed to stop the bootstrap.", e); if (!error) { error = e; } } if (this.onbootstraperror && error) { this.onbootstraperror(error); } this.#bootstrapPromiseResolve(false); } }