Loading toolkit/components/tor-launcher/TorStartupService.sys.mjs +3 −2 Changes for toolkit/components/tor-launcher/TorStartupService.sys.mjs: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -30,15 +30,16 @@ export class TorStartupService { } } async #init() { #init() { Services.obs.addObserver(this, BrowserTopics.QuitApplicationGranted); lazy.TorSettings.init(); // Theoretically, build() is expected to await the initialization of the // provider, and anything needing the Tor Provider should be able to just // await on TorProviderBuilder.build(). lazy.TorProviderBuilder.init(); await lazy.TorSettings.init(); lazy.TorConnect.init(); gInited = true; Loading toolkit/modules/Moat.sys.mjs +15 −5 Changes for toolkit/modules/Moat.sys.mjs: 15 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -2,13 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { TorBridgeSource } from "resource://gre/modules/TorSettings.sys.mjs"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { DomainFrontRequestBuilder: "resource://gre/modules/DomainFrontedRequests.sys.mjs", TorBridgeSource: "resource://gre/modules/TorSettings.sys.mjs", TorSettings: "resource://gre/modules/TorSettings.sys.mjs", }); const TorLauncherPrefs = Object.freeze({ Loading Loading @@ -211,13 +211,23 @@ export class MoatRPC { }; switch (settings.bridges.source) { case "builtin": retval.bridges.source = TorBridgeSource.BuiltIn; retval.bridges.source = lazy.TorBridgeSource.BuiltIn; retval.bridges.builtin_type = settings.bridges.type; // TorSettings will ignore strings for built-in bridges, and use the // ones it already knows, instead. // ones it already knows, instead. However, when we try these settings // in the connect assist, we skip TorSettings. Therefore, we set the // lines also here (the ones we already known, not the ones we receive // from Moat). This needs TorSettings to be initialized, which by now // should have already happened (this method is used only by TorConnect, // that needs TorSettings to be initialized). // In any case, getBuiltinBridges will throw if the data is not ready, // yet. retval.bridges.bridge_strings = lazy.TorSettings.getBuiltinBridges( settings.bridges.type ); break; case "bridgedb": retval.bridges.source = TorBridgeSource.BridgeDB; retval.bridges.source = lazy.TorBridgeSource.BridgeDB; if (settings.bridges.bridge_strings) { retval.bridges.bridge_strings = settings.bridges.bridge_strings; } else { Loading toolkit/modules/TorConnect.sys.mjs +62 −32 Changes for toolkit/modules/TorConnect.sys.mjs: 62 added lines, 32 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { MoatRPC: "resource://gre/modules/Moat.sys.mjs", TorBootstrapRequest: "resource://gre/modules/TorBootstrapRequest.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); // TODO: Should we move this to the about:torconnect actor? Loading @@ -19,10 +20,7 @@ ChromeUtils.defineModuleGetter( ); import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs"; import { TorSettings, TorSettingsTopics, } from "resource://gre/modules/TorSettings.sys.mjs"; import { TorSettings } from "resource://gre/modules/TorSettings.sys.mjs"; import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs"; Loading Loading @@ -650,10 +648,22 @@ export const TorConnect = (() => { } } // apply each of our settings and try to bootstrap with each const restoreOriginalSettings = async () => { try { this.originalSettings = TorSettings.getSettings(); await TorSettings.applySettings(); } catch (e) { // We cannot do much if the original settings were bad or // if the connection closed, so just report it in the // console. console.warn( "TorConnect: Failed to restore original settings.", e ); } }; // apply each of our settings and try to bootstrap with each try { for (const [ index, currentSetting, Loading @@ -669,8 +679,26 @@ export const TorConnect = (() => { }/${this.settings.length}` ); TorSettings.setSettings(currentSetting); await TorSettings.applySettings(); // Send the new settings directly to the provider. We will // save them only if the bootstrap succeeds. // FIXME: We should somehow signal TorSettings users that we // have set custom settings, and they should not apply // theirs until we are done with trying ours. // Otherwise, the new settings provided by the user while we // were bootstrapping could be the ones that cause the // bootstrap to succeed, but we overwrite them (unless we // backup the original settings, and then save our new // settings only if they have not changed). // Another idea (maybe easier to implement) is to disable // the settings UI while *any* bootstrap is going on. // This is also documented in tor-browser#41921. const provider = await lazy.TorProviderBuilder.build(); // We need to merge with old settings, in case the user is // using a proxy or is behind a firewall. await provider.writeSettings({ ...TorSettings.getSettings(), ...currentSetting, }); // build out our bootstrap request const tbr = new lazy.TorBootstrapRequest(); Loading @@ -687,6 +715,7 @@ export const TorConnect = (() => { this.on_transition = async nextState => { if (nextState === TorConnectState.Configuring) { await tbr.cancel(); await restoreOriginalSettings(); } resolve(); }; Loading @@ -694,23 +723,20 @@ export const TorConnect = (() => { // begin bootstrap if (await tbr.bootstrap()) { // persist the current settings to preferences TorSettings.setSettings(currentSetting); TorSettings.saveToPrefs(); await TorSettings.applySettings(); TorConnect._changeState(TorConnectState.Bootstrapped); return; } } // bootstrapped failed for all potential settings, so reset daemon to use original TorSettings.setSettings(this.originalSettings); // The original settings should be good, so we save them to // preferences before trying to apply them, as it might fail // if the actual problem is with the connection to the control // port. // FIXME: We should handle this case in a better way. TorSettings.saveToPrefs(); await TorSettings.applySettings(); // Bootstrap failed for all potential settings, so restore the // original settings the provider. await restoreOriginalSettings(); // only explicitly change state here if something else has not transitioned us // Only explicitly change state here if something else has not // transitioned us. if (!this.transitioning) { throw_error( TorStrings.torConnect.autoBootstrappingFailed, Loading @@ -719,18 +745,8 @@ export const TorConnect = (() => { } return; } catch (err) { // restore original settings in case of error try { TorSettings.setSettings(this.originalSettings); // As above TorSettings.saveToPrefs(); await TorSettings.applySettings(); } catch (errRestore) { console.log( `TorConnect: Failed to restore original settings => ${errRestore}` ); } // throw to outer catch to transition us await restoreOriginalSettings(); // throw to outer catch to transition us. throw err; } } catch (err) { Loading Loading @@ -877,6 +893,14 @@ export const TorConnect = (() => { console.log(`TorConnect: Observing topic '${addTopic}'`); }; // Wait for TorSettings, as we will need it. // We will wait for a TorProvider only after TorSettings is ready, // because the TorProviderBuilder initialization might not have finished // at this point, and TorSettings initialization is a prerequisite for // having a provider. // So, we prefer initializing TorConnect as soon as possible, so that // the UI will be able to detect it is in the Initializing state and act // consequently. TorSettings.initializedPromise.then(() => this._settingsInitialized()); // register the Tor topics we always care about Loading Loading @@ -918,19 +942,25 @@ export const TorConnect = (() => { } }, _settingsInitialized() { async _settingsInitialized() { // TODO: Handle failures here, instead of the prompt to restart the // daemon when it exits (tor-browser#21053, tor-browser#41921). await lazy.TorProviderBuilder.build(); // tor-browser#41907: This is only a workaround to avoid users being // bounced back to the initial panel without any explanation. // Longer term we should disable the clickable elements, or find a UX // to prevent this from happening (e.g., allow buttons to be clicked, // but show an intermediate starting state, or a message that tor is // starting while the butons are disabled, etc...). // See also tor-browser#41921. if (this.state !== TorConnectState.Initial) { console.warn( "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification." "TorConnect: The TorProvider was built after the state had already changed." ); return; } console.log("TorConnect: The TorProvider is ready, changing state."); if (this.shouldQuickStart) { // Quickstart this._changeState(TorConnectState.Bootstrapping); Loading toolkit/modules/TorSettings.sys.mjs +20 −140 Changes for toolkit/modules/TorSettings.sys.mjs: 20 added lines, 140 removed lines. Original line number Diff line number Diff line Loading @@ -6,10 +6,9 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs", Lox: "resource://gre/modules/Lox.sys.mjs", TorParsers: "resource://gre/modules/TorParsers.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); ChromeUtils.defineLazyGetter(lazy, "logger", () => { Loading Loading @@ -71,20 +70,6 @@ const TorSettingsPrefs = Object.freeze({ }, }); /* Config Keys used to configure tor daemon */ const TorConfigKeys = Object.freeze({ useBridges: "UseBridges", bridgeList: "Bridge", socks4Proxy: "Socks4Proxy", socks5Proxy: "Socks5Proxy", socks5ProxyUsername: "Socks5ProxyUsername", socks5ProxyPassword: "Socks5ProxyPassword", httpsProxy: "HTTPSProxy", httpsProxyAuthenticator: "HTTPSProxyAuthenticator", reachableAddresses: "ReachableAddresses", clientTransportPlugin: "ClientTransportPlugin", }); export const TorBridgeSource = Object.freeze({ Invalid: -1, BuiltIn: 0, Loading Loading @@ -322,7 +307,7 @@ class TorSettingsImpl { if (!val) { return; } const bridgeStrings = this.#getBuiltinBridges(val); const bridgeStrings = this.getBuiltinBridges(val); if (bridgeStrings.length) { this.bridges.bridge_strings = bridgeStrings; return; Loading Loading @@ -659,14 +644,17 @@ class TorSettingsImpl { * @param {string} pt The pluggable transport to return the lines for * @returns {string[]} The bridge lines in random order */ #getBuiltinBridges(pt) { getBuiltinBridges(pt) { if (!this.#allowUninitialized) { this.#checkIfInitialized(); } // Shuffle so that Tor Browser users do not all try the built-in bridges in // the same order. return arrayShuffle(this.#builtinBridges[pt] ?? []); } /** * Load or init our settings, and register observers. * Load or init our settings. */ async init() { if (this.#initialized) { Loading @@ -677,6 +665,7 @@ class TorSettingsImpl { await this.#initInternal(); this.#initialized = true; this.#initComplete(); Services.obs.notifyObservers(null, TorSettingsTopics.Ready); } catch (e) { this.#initFailed(e); throw e; Loading @@ -698,19 +687,18 @@ class TorSettingsImpl { lazy.logger.error("Could not load the built-in PT config.", e); } // Initialize this before loading from prefs because we need Lox initialized before // any calls to Lox.getBridges() // Initialize this before loading from prefs because we need Lox initialized // before any calls to Lox.getBridges(). try { await lazy.Lox.init(); } catch (e) { lazy.logger.error("Could not initialize Lox.", e.type); } // TODO: We could use a shared promise, and wait for it to be fullfilled // instead of Service.obs. if (lazy.TorLauncherUtil.shouldStartAndOwnTor) { // if the settings branch exists, load settings from prefs if (Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)) { if ( lazy.TorLauncherUtil.shouldStartAndOwnTor && Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false) ) { // Do not want notifications for initially loaded prefs. this.freezeNotifications(); try { Loading @@ -722,21 +710,12 @@ class TorSettingsImpl { this.thawNotifications(); } } try { const provider = await lazy.TorProviderBuilder.build(); if (provider.isRunning) { this.#handleProcessReady(); // No need to add an observer to call this again. return; } } catch {} Services.obs.addObserver(this, lazy.TorProviderTopics.ProcessIsReady); } lazy.logger.info("Ready"); } /** * Unload or uninit our settings, and unregister observers. * Unload or uninit our settings. */ async uninit() { await lazy.Lox.uninit(); Loading Loading @@ -764,34 +743,6 @@ class TorSettingsImpl { return this.#initialized; } /** * Wait for relevant life-cycle events to apply saved settings. */ async observe(subject, topic, data) { lazy.logger.debug(`Observed ${topic}`); switch (topic) { case lazy.TorProviderTopics.ProcessIsReady: Services.obs.removeObserver( this, lazy.TorProviderTopics.ProcessIsReady ); await this.#handleProcessReady(); break; } } /** * Apply the settings once the tor provider is ready and notify any observer * that the settings can be used. */ async #handleProcessReady() { // push down settings to tor await this.#applySettings(true); lazy.logger.info("Ready"); Services.obs.notifyObservers(null, TorSettingsTopics.Ready); } /** * Load our settings from prefs. */ Loading Loading @@ -972,85 +923,14 @@ class TorSettingsImpl { /** * Push our settings down to the tor provider. * * Even though this introduces a circular depdency, it makes the API nicer for * frontend consumers. */ async applySettings() { this.#checkIfInitialized(); return this.#applySettings(false); } /** * Internal implementation of applySettings that does not check if we are * initialized. */ async #applySettings(allowUninitialized) { lazy.logger.debug("#applySettings()"); this.#cleanupSettings(); const settingsMap = new Map(); // #applySettings can be called only when #allowUninitialized is false this.#allowUninitialized = allowUninitialized; try { /* Bridges */ const haveBridges = this.bridges.enabled && !!this.bridges.bridge_strings.length; settingsMap.set(TorConfigKeys.useBridges, haveBridges); if (haveBridges) { settingsMap.set(TorConfigKeys.bridgeList, this.bridges.bridge_strings); } else { settingsMap.set(TorConfigKeys.bridgeList, null); } /* Proxy */ settingsMap.set(TorConfigKeys.socks4Proxy, null); settingsMap.set(TorConfigKeys.socks5Proxy, null); settingsMap.set(TorConfigKeys.socks5ProxyUsername, null); settingsMap.set(TorConfigKeys.socks5ProxyPassword, null); settingsMap.set(TorConfigKeys.httpsProxy, null); settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null); if (this.proxy.enabled) { const address = this.proxy.address; const port = this.proxy.port; const username = this.proxy.username; const password = this.proxy.password; switch (this.proxy.type) { case TorProxyType.Socks4: settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`); break; case TorProxyType.Socks5: settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`); settingsMap.set(TorConfigKeys.socks5ProxyUsername, username); settingsMap.set(TorConfigKeys.socks5ProxyPassword, password); break; case TorProxyType.HTTPS: settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`); settingsMap.set( TorConfigKeys.httpsProxyAuthenticator, `${username}:${password}` ); break; } } /* Firewall */ if (this.firewall.enabled) { const reachableAddresses = this.firewall.allowed_ports .map(port => `*:${port}`) .join(","); settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses); } else { settingsMap.set(TorConfigKeys.reachableAddresses, null); } } finally { this.#allowUninitialized = false; } /* Push to Tor */ const provider = await lazy.TorProviderBuilder.build(); await provider.writeSettings(settingsMap); await provider.writeSettings(this.getSettings()); } /** Loading Loading
toolkit/components/tor-launcher/TorStartupService.sys.mjs +3 −2 Changes for toolkit/components/tor-launcher/TorStartupService.sys.mjs: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -30,15 +30,16 @@ export class TorStartupService { } } async #init() { #init() { Services.obs.addObserver(this, BrowserTopics.QuitApplicationGranted); lazy.TorSettings.init(); // Theoretically, build() is expected to await the initialization of the // provider, and anything needing the Tor Provider should be able to just // await on TorProviderBuilder.build(). lazy.TorProviderBuilder.init(); await lazy.TorSettings.init(); lazy.TorConnect.init(); gInited = true; Loading
toolkit/modules/Moat.sys.mjs +15 −5 Changes for toolkit/modules/Moat.sys.mjs: 15 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -2,13 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { TorBridgeSource } from "resource://gre/modules/TorSettings.sys.mjs"; const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { DomainFrontRequestBuilder: "resource://gre/modules/DomainFrontedRequests.sys.mjs", TorBridgeSource: "resource://gre/modules/TorSettings.sys.mjs", TorSettings: "resource://gre/modules/TorSettings.sys.mjs", }); const TorLauncherPrefs = Object.freeze({ Loading Loading @@ -211,13 +211,23 @@ export class MoatRPC { }; switch (settings.bridges.source) { case "builtin": retval.bridges.source = TorBridgeSource.BuiltIn; retval.bridges.source = lazy.TorBridgeSource.BuiltIn; retval.bridges.builtin_type = settings.bridges.type; // TorSettings will ignore strings for built-in bridges, and use the // ones it already knows, instead. // ones it already knows, instead. However, when we try these settings // in the connect assist, we skip TorSettings. Therefore, we set the // lines also here (the ones we already known, not the ones we receive // from Moat). This needs TorSettings to be initialized, which by now // should have already happened (this method is used only by TorConnect, // that needs TorSettings to be initialized). // In any case, getBuiltinBridges will throw if the data is not ready, // yet. retval.bridges.bridge_strings = lazy.TorSettings.getBuiltinBridges( settings.bridges.type ); break; case "bridgedb": retval.bridges.source = TorBridgeSource.BridgeDB; retval.bridges.source = lazy.TorBridgeSource.BridgeDB; if (settings.bridges.bridge_strings) { retval.bridges.bridge_strings = settings.bridges.bridge_strings; } else { Loading
toolkit/modules/TorConnect.sys.mjs +62 −32 Changes for toolkit/modules/TorConnect.sys.mjs: 62 added lines, 32 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { MoatRPC: "resource://gre/modules/Moat.sys.mjs", TorBootstrapRequest: "resource://gre/modules/TorBootstrapRequest.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); // TODO: Should we move this to the about:torconnect actor? Loading @@ -19,10 +20,7 @@ ChromeUtils.defineModuleGetter( ); import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs"; import { TorSettings, TorSettingsTopics, } from "resource://gre/modules/TorSettings.sys.mjs"; import { TorSettings } from "resource://gre/modules/TorSettings.sys.mjs"; import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs"; Loading Loading @@ -650,10 +648,22 @@ export const TorConnect = (() => { } } // apply each of our settings and try to bootstrap with each const restoreOriginalSettings = async () => { try { this.originalSettings = TorSettings.getSettings(); await TorSettings.applySettings(); } catch (e) { // We cannot do much if the original settings were bad or // if the connection closed, so just report it in the // console. console.warn( "TorConnect: Failed to restore original settings.", e ); } }; // apply each of our settings and try to bootstrap with each try { for (const [ index, currentSetting, Loading @@ -669,8 +679,26 @@ export const TorConnect = (() => { }/${this.settings.length}` ); TorSettings.setSettings(currentSetting); await TorSettings.applySettings(); // Send the new settings directly to the provider. We will // save them only if the bootstrap succeeds. // FIXME: We should somehow signal TorSettings users that we // have set custom settings, and they should not apply // theirs until we are done with trying ours. // Otherwise, the new settings provided by the user while we // were bootstrapping could be the ones that cause the // bootstrap to succeed, but we overwrite them (unless we // backup the original settings, and then save our new // settings only if they have not changed). // Another idea (maybe easier to implement) is to disable // the settings UI while *any* bootstrap is going on. // This is also documented in tor-browser#41921. const provider = await lazy.TorProviderBuilder.build(); // We need to merge with old settings, in case the user is // using a proxy or is behind a firewall. await provider.writeSettings({ ...TorSettings.getSettings(), ...currentSetting, }); // build out our bootstrap request const tbr = new lazy.TorBootstrapRequest(); Loading @@ -687,6 +715,7 @@ export const TorConnect = (() => { this.on_transition = async nextState => { if (nextState === TorConnectState.Configuring) { await tbr.cancel(); await restoreOriginalSettings(); } resolve(); }; Loading @@ -694,23 +723,20 @@ export const TorConnect = (() => { // begin bootstrap if (await tbr.bootstrap()) { // persist the current settings to preferences TorSettings.setSettings(currentSetting); TorSettings.saveToPrefs(); await TorSettings.applySettings(); TorConnect._changeState(TorConnectState.Bootstrapped); return; } } // bootstrapped failed for all potential settings, so reset daemon to use original TorSettings.setSettings(this.originalSettings); // The original settings should be good, so we save them to // preferences before trying to apply them, as it might fail // if the actual problem is with the connection to the control // port. // FIXME: We should handle this case in a better way. TorSettings.saveToPrefs(); await TorSettings.applySettings(); // Bootstrap failed for all potential settings, so restore the // original settings the provider. await restoreOriginalSettings(); // only explicitly change state here if something else has not transitioned us // Only explicitly change state here if something else has not // transitioned us. if (!this.transitioning) { throw_error( TorStrings.torConnect.autoBootstrappingFailed, Loading @@ -719,18 +745,8 @@ export const TorConnect = (() => { } return; } catch (err) { // restore original settings in case of error try { TorSettings.setSettings(this.originalSettings); // As above TorSettings.saveToPrefs(); await TorSettings.applySettings(); } catch (errRestore) { console.log( `TorConnect: Failed to restore original settings => ${errRestore}` ); } // throw to outer catch to transition us await restoreOriginalSettings(); // throw to outer catch to transition us. throw err; } } catch (err) { Loading Loading @@ -877,6 +893,14 @@ export const TorConnect = (() => { console.log(`TorConnect: Observing topic '${addTopic}'`); }; // Wait for TorSettings, as we will need it. // We will wait for a TorProvider only after TorSettings is ready, // because the TorProviderBuilder initialization might not have finished // at this point, and TorSettings initialization is a prerequisite for // having a provider. // So, we prefer initializing TorConnect as soon as possible, so that // the UI will be able to detect it is in the Initializing state and act // consequently. TorSettings.initializedPromise.then(() => this._settingsInitialized()); // register the Tor topics we always care about Loading Loading @@ -918,19 +942,25 @@ export const TorConnect = (() => { } }, _settingsInitialized() { async _settingsInitialized() { // TODO: Handle failures here, instead of the prompt to restart the // daemon when it exits (tor-browser#21053, tor-browser#41921). await lazy.TorProviderBuilder.build(); // tor-browser#41907: This is only a workaround to avoid users being // bounced back to the initial panel without any explanation. // Longer term we should disable the clickable elements, or find a UX // to prevent this from happening (e.g., allow buttons to be clicked, // but show an intermediate starting state, or a message that tor is // starting while the butons are disabled, etc...). // See also tor-browser#41921. if (this.state !== TorConnectState.Initial) { console.warn( "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification." "TorConnect: The TorProvider was built after the state had already changed." ); return; } console.log("TorConnect: The TorProvider is ready, changing state."); if (this.shouldQuickStart) { // Quickstart this._changeState(TorConnectState.Bootstrapping); Loading
toolkit/modules/TorSettings.sys.mjs +20 −140 Changes for toolkit/modules/TorSettings.sys.mjs: 20 added lines, 140 removed lines. Original line number Diff line number Diff line Loading @@ -6,10 +6,9 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs", Lox: "resource://gre/modules/Lox.sys.mjs", TorParsers: "resource://gre/modules/TorParsers.sys.mjs", TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs", }); ChromeUtils.defineLazyGetter(lazy, "logger", () => { Loading Loading @@ -71,20 +70,6 @@ const TorSettingsPrefs = Object.freeze({ }, }); /* Config Keys used to configure tor daemon */ const TorConfigKeys = Object.freeze({ useBridges: "UseBridges", bridgeList: "Bridge", socks4Proxy: "Socks4Proxy", socks5Proxy: "Socks5Proxy", socks5ProxyUsername: "Socks5ProxyUsername", socks5ProxyPassword: "Socks5ProxyPassword", httpsProxy: "HTTPSProxy", httpsProxyAuthenticator: "HTTPSProxyAuthenticator", reachableAddresses: "ReachableAddresses", clientTransportPlugin: "ClientTransportPlugin", }); export const TorBridgeSource = Object.freeze({ Invalid: -1, BuiltIn: 0, Loading Loading @@ -322,7 +307,7 @@ class TorSettingsImpl { if (!val) { return; } const bridgeStrings = this.#getBuiltinBridges(val); const bridgeStrings = this.getBuiltinBridges(val); if (bridgeStrings.length) { this.bridges.bridge_strings = bridgeStrings; return; Loading Loading @@ -659,14 +644,17 @@ class TorSettingsImpl { * @param {string} pt The pluggable transport to return the lines for * @returns {string[]} The bridge lines in random order */ #getBuiltinBridges(pt) { getBuiltinBridges(pt) { if (!this.#allowUninitialized) { this.#checkIfInitialized(); } // Shuffle so that Tor Browser users do not all try the built-in bridges in // the same order. return arrayShuffle(this.#builtinBridges[pt] ?? []); } /** * Load or init our settings, and register observers. * Load or init our settings. */ async init() { if (this.#initialized) { Loading @@ -677,6 +665,7 @@ class TorSettingsImpl { await this.#initInternal(); this.#initialized = true; this.#initComplete(); Services.obs.notifyObservers(null, TorSettingsTopics.Ready); } catch (e) { this.#initFailed(e); throw e; Loading @@ -698,19 +687,18 @@ class TorSettingsImpl { lazy.logger.error("Could not load the built-in PT config.", e); } // Initialize this before loading from prefs because we need Lox initialized before // any calls to Lox.getBridges() // Initialize this before loading from prefs because we need Lox initialized // before any calls to Lox.getBridges(). try { await lazy.Lox.init(); } catch (e) { lazy.logger.error("Could not initialize Lox.", e.type); } // TODO: We could use a shared promise, and wait for it to be fullfilled // instead of Service.obs. if (lazy.TorLauncherUtil.shouldStartAndOwnTor) { // if the settings branch exists, load settings from prefs if (Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)) { if ( lazy.TorLauncherUtil.shouldStartAndOwnTor && Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false) ) { // Do not want notifications for initially loaded prefs. this.freezeNotifications(); try { Loading @@ -722,21 +710,12 @@ class TorSettingsImpl { this.thawNotifications(); } } try { const provider = await lazy.TorProviderBuilder.build(); if (provider.isRunning) { this.#handleProcessReady(); // No need to add an observer to call this again. return; } } catch {} Services.obs.addObserver(this, lazy.TorProviderTopics.ProcessIsReady); } lazy.logger.info("Ready"); } /** * Unload or uninit our settings, and unregister observers. * Unload or uninit our settings. */ async uninit() { await lazy.Lox.uninit(); Loading Loading @@ -764,34 +743,6 @@ class TorSettingsImpl { return this.#initialized; } /** * Wait for relevant life-cycle events to apply saved settings. */ async observe(subject, topic, data) { lazy.logger.debug(`Observed ${topic}`); switch (topic) { case lazy.TorProviderTopics.ProcessIsReady: Services.obs.removeObserver( this, lazy.TorProviderTopics.ProcessIsReady ); await this.#handleProcessReady(); break; } } /** * Apply the settings once the tor provider is ready and notify any observer * that the settings can be used. */ async #handleProcessReady() { // push down settings to tor await this.#applySettings(true); lazy.logger.info("Ready"); Services.obs.notifyObservers(null, TorSettingsTopics.Ready); } /** * Load our settings from prefs. */ Loading Loading @@ -972,85 +923,14 @@ class TorSettingsImpl { /** * Push our settings down to the tor provider. * * Even though this introduces a circular depdency, it makes the API nicer for * frontend consumers. */ async applySettings() { this.#checkIfInitialized(); return this.#applySettings(false); } /** * Internal implementation of applySettings that does not check if we are * initialized. */ async #applySettings(allowUninitialized) { lazy.logger.debug("#applySettings()"); this.#cleanupSettings(); const settingsMap = new Map(); // #applySettings can be called only when #allowUninitialized is false this.#allowUninitialized = allowUninitialized; try { /* Bridges */ const haveBridges = this.bridges.enabled && !!this.bridges.bridge_strings.length; settingsMap.set(TorConfigKeys.useBridges, haveBridges); if (haveBridges) { settingsMap.set(TorConfigKeys.bridgeList, this.bridges.bridge_strings); } else { settingsMap.set(TorConfigKeys.bridgeList, null); } /* Proxy */ settingsMap.set(TorConfigKeys.socks4Proxy, null); settingsMap.set(TorConfigKeys.socks5Proxy, null); settingsMap.set(TorConfigKeys.socks5ProxyUsername, null); settingsMap.set(TorConfigKeys.socks5ProxyPassword, null); settingsMap.set(TorConfigKeys.httpsProxy, null); settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null); if (this.proxy.enabled) { const address = this.proxy.address; const port = this.proxy.port; const username = this.proxy.username; const password = this.proxy.password; switch (this.proxy.type) { case TorProxyType.Socks4: settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`); break; case TorProxyType.Socks5: settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`); settingsMap.set(TorConfigKeys.socks5ProxyUsername, username); settingsMap.set(TorConfigKeys.socks5ProxyPassword, password); break; case TorProxyType.HTTPS: settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`); settingsMap.set( TorConfigKeys.httpsProxyAuthenticator, `${username}:${password}` ); break; } } /* Firewall */ if (this.firewall.enabled) { const reachableAddresses = this.firewall.allowed_ports .map(port => `*:${port}`) .join(","); settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses); } else { settingsMap.set(TorConfigKeys.reachableAddresses, null); } } finally { this.#allowUninitialized = false; } /* Push to Tor */ const provider = await lazy.TorProviderBuilder.build(); await provider.writeSettings(settingsMap); await provider.writeSettings(this.getSettings()); } /** Loading