Pier Angelo Vendrame pushed to branch tor-browser-115.8.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
9cecc61f
by Pier Angelo Vendrame at 2024-03-11T09:33:51+01:00
-
138e8d6b
by Pier Angelo Vendrame at 2024-03-11T16:19:47+01:00
-
6265cc34
by Pier Angelo Vendrame at 2024-03-11T16:19:52+01:00
-
e409c32a
by Pier Angelo Vendrame at 2024-03-11T16:19:52+01:00
-
f8451ae0
by Pier Angelo Vendrame at 2024-03-11T16:19:53+01:00
10 changed files:
- browser/components/torpreferences/content/connectionPane.js
- browser/components/torpreferences/content/connectionSettingsDialog.js
- toolkit/components/tor-launcher/TorControlPort.sys.mjs
- toolkit/components/tor-launcher/TorProvider.sys.mjs
- toolkit/components/tor-launcher/TorProviderBuilder.sys.mjs
- toolkit/components/tor-launcher/TorStartupService.sys.mjs
- toolkit/modules/Moat.sys.mjs
- toolkit/modules/TorAndroidIntegration.sys.mjs
- toolkit/modules/TorConnect.sys.mjs
- toolkit/modules/TorSettings.sys.mjs
Changes:
| ... | ... | @@ -114,10 +114,9 @@ async function setTorSettings(changes) { |
| 114 | 114 | // This will trigger TorSettings.#cleanupSettings()
|
| 115 | 115 | TorSettings.saveToPrefs();
|
| 116 | 116 | try {
|
| 117 | - // May throw.
|
|
| 118 | 117 | await TorSettings.applySettings();
|
| 119 | 118 | } catch (e) {
|
| 120 | - console.error("Failed to save Tor settings", e);
|
|
| 119 | + console.error("Failed to apply Tor settings", e);
|
|
| 121 | 120 | }
|
| 122 | 121 | } finally {
|
| 123 | 122 | TorSettings.thawNotifications();
|
| ... | ... | @@ -362,6 +362,8 @@ const gConnectionSettingsDialog = { |
| 362 | 362 | }
|
| 363 | 363 | |
| 364 | 364 | TorSettings.saveToPrefs();
|
| 365 | + // FIXME: What if this fails? Should we prevent the dialog to close and show
|
|
| 366 | + // an error?
|
|
| 365 | 367 | TorSettings.applySettings();
|
| 366 | 368 | },
|
| 367 | 369 | };
|
| ... | ... | @@ -838,10 +838,12 @@ export class TorController { |
| 838 | 838 | /**
|
| 839 | 839 | * Send multiple configuration values to tor.
|
| 840 | 840 | *
|
| 841 | - * @param {object} values The values to set
|
|
| 841 | + * @param {Array} values The values to set. It should be an array of
|
|
| 842 | + * [key, value] pairs to pass to SETCONF. Keys can be repeated, and array
|
|
| 843 | + * values will be automatically unrolled.
|
|
| 842 | 844 | */
|
| 843 | 845 | async setConf(values) {
|
| 844 | - const args = Object.entries(values)
|
|
| 846 | + const args = values
|
|
| 845 | 847 | .flatMap(([key, value]) => {
|
| 846 | 848 | if (value === undefined || value === null) {
|
| 847 | 849 | return [key];
|
| ... | ... | @@ -871,7 +873,7 @@ export class TorController { |
| 871 | 873 | * @param {boolean} enabled Tell whether the network should be enabled
|
| 872 | 874 | */
|
| 873 | 875 | async setNetworkEnabled(enabled) {
|
| 874 | - return this.setConf({ DisableNetwork: !enabled });
|
|
| 876 | + return this.setConf([["DisableNetwork", !enabled]]);
|
|
| 875 | 877 | }
|
| 876 | 878 | |
| 877 | 879 | /**
|
| ... | ... | @@ -15,6 +15,8 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 15 | 15 | TorController: "resource://gre/modules/TorControlPort.sys.mjs",
|
| 16 | 16 | TorProcess: "resource://gre/modules/TorProcess.sys.mjs",
|
| 17 | 17 | TorProcessAndroid: "resource://gre/modules/TorProcessAndroid.sys.mjs",
|
| 18 | + TorProxyType: "resource://gre/modules/TorSettings.sys.mjs",
|
|
| 19 | + TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
|
|
| 18 | 20 | });
|
| 19 | 21 | |
| 20 | 22 | const logger = new ConsoleAPI({
|
| ... | ... | @@ -73,6 +75,20 @@ const Preferences = Object.freeze({ |
| 73 | 75 | PromptAtStartup: "extensions.torlauncher.prompt_at_startup",
|
| 74 | 76 | });
|
| 75 | 77 | |
| 78 | +/* Config Keys used to configure tor daemon */
|
|
| 79 | +const TorConfigKeys = Object.freeze({
|
|
| 80 | + useBridges: "UseBridges",
|
|
| 81 | + bridgeList: "Bridge",
|
|
| 82 | + socks4Proxy: "Socks4Proxy",
|
|
| 83 | + socks5Proxy: "Socks5Proxy",
|
|
| 84 | + socks5ProxyUsername: "Socks5ProxyUsername",
|
|
| 85 | + socks5ProxyPassword: "Socks5ProxyPassword",
|
|
| 86 | + httpsProxy: "HTTPSProxy",
|
|
| 87 | + httpsProxyAuthenticator: "HTTPSProxyAuthenticator",
|
|
| 88 | + reachableAddresses: "ReachableAddresses",
|
|
| 89 | + clientTransportPlugin: "ClientTransportPlugin",
|
|
| 90 | +});
|
|
| 91 | + |
|
| 76 | 92 | /**
|
| 77 | 93 | * This is a Tor provider for the C Tor daemon.
|
| 78 | 94 | *
|
| ... | ... | @@ -166,15 +182,6 @@ export class TorProvider { |
| 166 | 182 | */
|
| 167 | 183 | #currentBridge = null;
|
| 168 | 184 | |
| 169 | - /**
|
|
| 170 | - * Maintain a map of tor settings set by Tor Browser so that we don't
|
|
| 171 | - * repeatedly set the same key/values over and over.
|
|
| 172 | - * This map contains string keys to primitives or array values.
|
|
| 173 | - *
|
|
| 174 | - * @type {Map<string, any>}
|
|
| 175 | - */
|
|
| 176 | - #settingsCache = new Map();
|
|
| 177 | - |
|
| 178 | 185 | /**
|
| 179 | 186 | * Starts a new tor process and connect to its control port, or connect to the
|
| 180 | 187 | * control port of an existing tor daemon.
|
| ... | ... | @@ -219,13 +226,22 @@ export class TorProvider { |
| 219 | 226 | throw e;
|
| 220 | 227 | }
|
| 221 | 228 | |
| 229 | + try {
|
|
| 230 | + await lazy.TorSettings.initializedPromise;
|
|
| 231 | + await this.writeSettings(lazy.TorSettings.getSettings());
|
|
| 232 | + } catch (e) {
|
|
| 233 | + logger.warn(
|
|
| 234 | + "Failed to initialize TorSettings or to write our settings, so uninitializing.",
|
|
| 235 | + e
|
|
| 236 | + );
|
|
| 237 | + this.uninit();
|
|
| 238 | + throw e;
|
|
| 239 | + }
|
|
| 240 | + |
|
| 222 | 241 | TorLauncherUtil.setProxyConfiguration(this.#socksSettings);
|
| 223 | 242 | |
| 224 | 243 | logger.info("The Tor provider is ready.");
|
| 225 | 244 | |
| 226 | - logger.debug(`Notifying ${TorProviderTopics.ProcessIsReady}`);
|
|
| 227 | - Services.obs.notifyObservers(null, TorProviderTopics.ProcessIsReady);
|
|
| 228 | - |
|
| 229 | 245 | // If we are using an external Tor daemon, we might need to fetch circuits
|
| 230 | 246 | // already, in case streams use them. Do not await because we do not want to
|
| 231 | 247 | // block the intialization on this (it should not fail anyway...).
|
| ... | ... | @@ -252,42 +268,74 @@ export class TorProvider { |
| 252 | 268 | |
| 253 | 269 | // Provider API
|
| 254 | 270 | |
| 255 | - async writeSettings(settingsObj) {
|
|
| 256 | - // TODO: Move the translation from settings object to settings understood by
|
|
| 257 | - // tor here.
|
|
| 258 | - const entries =
|
|
| 259 | - settingsObj instanceof Map
|
|
| 260 | - ? Array.from(settingsObj.entries())
|
|
| 261 | - : Object.entries(settingsObj);
|
|
| 262 | - // only write settings that have changed
|
|
| 263 | - const newSettings = entries.filter(([setting, value]) => {
|
|
| 264 | - if (!this.#settingsCache.has(setting)) {
|
|
| 265 | - // no cached setting, so write
|
|
| 266 | - return true;
|
|
| 267 | - }
|
|
| 271 | + /**
|
|
| 272 | + * Send settings to the tor daemon.
|
|
| 273 | + *
|
|
| 274 | + * @param {object} settings A settings object, as returned by
|
|
| 275 | + * TorSettings.getSettings(). This allow to try settings without passing
|
|
| 276 | + * through TorSettings.
|
|
| 277 | + */
|
|
| 278 | + async writeSettings(settings) {
|
|
| 279 | + logger.debug("TorProvider.writeSettings", settings);
|
|
| 280 | + const torSettings = new Map();
|
|
| 281 | + |
|
| 282 | + // Bridges
|
|
| 283 | + const haveBridges =
|
|
| 284 | + settings.bridges?.enabled && !!settings.bridges.bridge_strings.length;
|
|
| 285 | + torSettings.set(TorConfigKeys.useBridges, haveBridges);
|
|
| 286 | + if (haveBridges) {
|
|
| 287 | + torSettings.set(
|
|
| 288 | + TorConfigKeys.bridgeList,
|
|
| 289 | + settings.bridges.bridge_strings
|
|
| 290 | + );
|
|
| 291 | + } else {
|
|
| 292 | + torSettings.set(TorConfigKeys.bridgeList, null);
|
|
| 293 | + }
|
|
| 268 | 294 | |
| 269 | - const cachedValue = this.#settingsCache.get(setting);
|
|
| 270 | - // Arrays are the only special case for which === could fail.
|
|
| 271 | - // The other values we accept (strings, booleans, numbers, null and
|
|
| 272 | - // undefined) work correctly with ===.
|
|
| 273 | - if (Array.isArray(value) && Array.isArray(cachedValue)) {
|
|
| 274 | - return (
|
|
| 275 | - value.length !== cachedValue.length ||
|
|
| 276 | - value.some((val, idx) => val !== cachedValue[idx])
|
|
| 295 | + // Proxy
|
|
| 296 | + torSettings.set(TorConfigKeys.socks4Proxy, null);
|
|
| 297 | + torSettings.set(TorConfigKeys.socks5Proxy, null);
|
|
| 298 | + torSettings.set(TorConfigKeys.socks5ProxyUsername, null);
|
|
| 299 | + torSettings.set(TorConfigKeys.socks5ProxyPassword, null);
|
|
| 300 | + torSettings.set(TorConfigKeys.httpsProxy, null);
|
|
| 301 | + torSettings.set(TorConfigKeys.httpsProxyAuthenticator, null);
|
|
| 302 | + if (settings.proxy && !settings.proxy.enabled) {
|
|
| 303 | + settings.proxy.type = null;
|
|
| 304 | + }
|
|
| 305 | + const address = settings.proxy?.address;
|
|
| 306 | + const port = settings.proxy?.port;
|
|
| 307 | + const username = settings.proxy?.username;
|
|
| 308 | + const password = settings.proxy?.password;
|
|
| 309 | + switch (settings.proxy?.type) {
|
|
| 310 | + case lazy.TorProxyType.Socks4:
|
|
| 311 | + torSettings.set(TorConfigKeys.socks4Proxy, `${address}:${port}`);
|
|
| 312 | + break;
|
|
| 313 | + case lazy.TorProxyType.Socks5:
|
|
| 314 | + torSettings.set(TorConfigKeys.socks5Proxy, `${address}:${port}`);
|
|
| 315 | + torSettings.set(TorConfigKeys.socks5ProxyUsername, username);
|
|
| 316 | + torSettings.set(TorConfigKeys.socks5ProxyPassword, password);
|
|
| 317 | + break;
|
|
| 318 | + case lazy.TorProxyType.HTTPS:
|
|
| 319 | + torSettings.set(TorConfigKeys.httpsProxy, `${address}:${port}`);
|
|
| 320 | + torSettings.set(
|
|
| 321 | + TorConfigKeys.httpsProxyAuthenticator,
|
|
| 322 | + `${username}:${password}`
|
|
| 277 | 323 | );
|
| 278 | - }
|
|
| 279 | - return value !== cachedValue;
|
|
| 280 | - });
|
|
| 281 | - |
|
| 282 | - // only write if new setting to save
|
|
| 283 | - if (newSettings.length) {
|
|
| 284 | - await this.#controller.setConf(Object.fromEntries(newSettings));
|
|
| 324 | + break;
|
|
| 325 | + }
|
|
| 285 | 326 | |
| 286 | - // save settings to cache after successfully writing to Tor
|
|
| 287 | - for (const [setting, value] of newSettings) {
|
|
| 288 | - this.#settingsCache.set(setting, value);
|
|
| 289 | - }
|
|
| 327 | + // Firewall
|
|
| 328 | + if (settings.firewall?.enabled) {
|
|
| 329 | + const reachableAddresses = settings.firewall.allowed_ports
|
|
| 330 | + .map(port => `*:${port}`)
|
|
| 331 | + .join(",");
|
|
| 332 | + torSettings.set(TorConfigKeys.reachableAddresses, reachableAddresses);
|
|
| 333 | + } else {
|
|
| 334 | + torSettings.set(TorConfigKeys.reachableAddresses, null);
|
|
| 290 | 335 | }
|
| 336 | + |
|
| 337 | + logger.debug("Mapped settings object", settings, torSettings);
|
|
| 338 | + await this.#controller.setConf(Array.from(torSettings));
|
|
| 291 | 339 | }
|
| 292 | 340 | |
| 293 | 341 | async flushSettings() {
|
| ... | ... | @@ -9,7 +9,6 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 9 | 9 | });
|
| 10 | 10 | |
| 11 | 11 | export const TorProviderTopics = Object.freeze({
|
| 12 | - ProcessIsReady: "TorProcessIsReady",
|
|
| 13 | 12 | ProcessExited: "TorProcessExited",
|
| 14 | 13 | BootstrapStatus: "TorBootstrapStatus",
|
| 15 | 14 | BootstrapError: "TorBootstrapError",
|
| ... | ... | @@ -31,15 +31,16 @@ export class TorStartupService { |
| 31 | 31 | }
|
| 32 | 32 | }
|
| 33 | 33 | |
| 34 | - async #init() {
|
|
| 34 | + #init() {
|
|
| 35 | 35 | Services.obs.addObserver(this, BrowserTopics.QuitApplicationGranted);
|
| 36 | 36 | |
| 37 | - // Do not await on this init. build() is expected to await the
|
|
| 38 | - // initialization, so anything that should need the Tor Provider should
|
|
| 39 | - // block there, instead.
|
|
| 37 | + lazy.TorSettings.init();
|
|
| 38 | + |
|
| 39 | + // Theoretically, build() is expected to await the initialization of the
|
|
| 40 | + // provider, and anything needing the Tor Provider should be able to just
|
|
| 41 | + // await on TorProviderBuilder.build().
|
|
| 40 | 42 | lazy.TorProviderBuilder.init();
|
| 41 | 43 | |
| 42 | - await lazy.TorSettings.init();
|
|
| 43 | 44 | lazy.TorConnect.init();
|
| 44 | 45 | |
| 45 | 46 | lazy.TorDomainIsolator.init();
|
| ... | ... | @@ -2,13 +2,13 @@ |
| 2 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| 3 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| 4 | 4 | |
| 5 | -import { TorBridgeSource } from "resource://gre/modules/TorSettings.sys.mjs";
|
|
| 6 | - |
|
| 7 | 5 | const lazy = {};
|
| 8 | 6 | |
| 9 | 7 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 10 | 8 | DomainFrontRequestBuilder:
|
| 11 | 9 | "resource://gre/modules/DomainFrontedRequests.sys.mjs",
|
| 10 | + TorBridgeSource: "resource://gre/modules/TorSettings.sys.mjs",
|
|
| 11 | + TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
|
|
| 12 | 12 | });
|
| 13 | 13 | |
| 14 | 14 | const TorLauncherPrefs = Object.freeze({
|
| ... | ... | @@ -211,13 +211,23 @@ export class MoatRPC { |
| 211 | 211 | };
|
| 212 | 212 | switch (settings.bridges.source) {
|
| 213 | 213 | case "builtin":
|
| 214 | - retval.bridges.source = TorBridgeSource.BuiltIn;
|
|
| 214 | + retval.bridges.source = lazy.TorBridgeSource.BuiltIn;
|
|
| 215 | 215 | retval.bridges.builtin_type = settings.bridges.type;
|
| 216 | 216 | // TorSettings will ignore strings for built-in bridges, and use the
|
| 217 | - // ones it already knows, instead.
|
|
| 217 | + // ones it already knows, instead. However, when we try these settings
|
|
| 218 | + // in the connect assist, we skip TorSettings. Therefore, we set the
|
|
| 219 | + // lines also here (the ones we already known, not the ones we receive
|
|
| 220 | + // from Moat). This needs TorSettings to be initialized, which by now
|
|
| 221 | + // should have already happened (this method is used only by TorConnect,
|
|
| 222 | + // that needs TorSettings to be initialized).
|
|
| 223 | + // In any case, getBuiltinBridges will throw if the data is not ready,
|
|
| 224 | + // yet.
|
|
| 225 | + retval.bridges.bridge_strings = lazy.TorSettings.getBuiltinBridges(
|
|
| 226 | + settings.bridges.type
|
|
| 227 | + );
|
|
| 218 | 228 | break;
|
| 219 | 229 | case "bridgedb":
|
| 220 | - retval.bridges.source = TorBridgeSource.BridgeDB;
|
|
| 230 | + retval.bridges.source = lazy.TorBridgeSource.BridgeDB;
|
|
| 221 | 231 | if (settings.bridges.bridge_strings) {
|
| 222 | 232 | retval.bridges.bridge_strings = settings.bridges.bridge_strings;
|
| 223 | 233 | } else {
|
| ... | ... | @@ -150,7 +150,7 @@ class TorAndroidIntegrationImpl { |
| 150 | 150 | lazy.TorSettings.saveToPrefs();
|
| 151 | 151 | }
|
| 152 | 152 | if (data.apply) {
|
| 153 | - lazy.TorSettings.applySettings();
|
|
| 153 | + await lazy.TorSettings.applySettings();
|
|
| 154 | 154 | }
|
| 155 | 155 | break;
|
| 156 | 156 | case ListenedEvents.settingsApply:
|
| ... | ... | @@ -2,14 +2,17 @@ |
| 2 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| 3 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| 4 | 4 | |
| 5 | +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
| 5 | 6 | import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs";
|
| 6 | 7 | |
| 7 | 8 | const lazy = {};
|
| 8 | 9 | |
| 9 | 10 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 11 | + ConsoleAPI: "resource://gre/modules/Console.sys.mjs",
|
|
| 10 | 12 | EventDispatcher: "resource://gre/modules/Messaging.sys.mjs",
|
| 11 | 13 | MoatRPC: "resource://gre/modules/Moat.sys.mjs",
|
| 12 | 14 | TorBootstrapRequest: "resource://gre/modules/TorBootstrapRequest.sys.mjs",
|
| 15 | + TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
|
| 13 | 16 | });
|
| 14 | 17 | |
| 15 | 18 | // TODO: Should we move this to the about:torconnect actor?
|
| ... | ... | @@ -20,10 +23,7 @@ ChromeUtils.defineModuleGetter( |
| 20 | 23 | );
|
| 21 | 24 | |
| 22 | 25 | import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs";
|
| 23 | -import {
|
|
| 24 | - TorSettings,
|
|
| 25 | - TorSettingsTopics,
|
|
| 26 | -} from "resource://gre/modules/TorSettings.sys.mjs";
|
|
| 26 | +import { TorSettings } from "resource://gre/modules/TorSettings.sys.mjs";
|
|
| 27 | 27 | |
| 28 | 28 | import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
|
| 29 | 29 | |
| ... | ... | @@ -40,6 +40,7 @@ const TorLauncherPrefs = Object.freeze({ |
| 40 | 40 | const TorConnectPrefs = Object.freeze({
|
| 41 | 41 | censorship_level: "torbrowser.debug.censorship_level",
|
| 42 | 42 | allow_internet_test: "torbrowser.bootstrap.allow_internet_test",
|
| 43 | + log_level: "torbrowser.bootstrap.log_level",
|
|
| 43 | 44 | });
|
| 44 | 45 | |
| 45 | 46 | export const TorConnectState = Object.freeze({
|
| ... | ... | @@ -59,6 +60,17 @@ export const TorConnectState = Object.freeze({ |
| 59 | 60 | Disabled: "Disabled",
|
| 60 | 61 | });
|
| 61 | 62 | |
| 63 | +XPCOMUtils.defineLazyGetter(
|
|
| 64 | + lazy,
|
|
| 65 | + "logger",
|
|
| 66 | + () =>
|
|
| 67 | + new lazy.ConsoleAPI({
|
|
| 68 | + maxLogLevel: "info",
|
|
| 69 | + maxLogLevelPref: TorConnectPrefs.log_level,
|
|
| 70 | + prefix: "TorConnect",
|
|
| 71 | + })
|
|
| 72 | +);
|
|
| 73 | + |
|
| 62 | 74 | /*
|
| 63 | 75 | TorConnect State Transitions
|
| 64 | 76 | |
| ... | ... | @@ -194,12 +206,12 @@ class StateCallback { |
| 194 | 206 | }
|
| 195 | 207 | |
| 196 | 208 | async begin(...args) {
|
| 197 | - console.log(`TorConnect: Entering ${this._state} state`);
|
|
| 209 | + lazy.logger.trace(`Entering ${this._state} state`);
|
|
| 198 | 210 | this._init();
|
| 199 | 211 | try {
|
| 200 | 212 | // this Promise will block until this StateCallback has completed its work
|
| 201 | 213 | await Promise.resolve(this._callback.call(this._context, ...args));
|
| 202 | - console.log(`TorConnect: Exited ${this._state} state`);
|
|
| 214 | + lazy.logger.info(`Exited ${this._state} state`);
|
|
| 203 | 215 | |
| 204 | 216 | // handled state transition
|
| 205 | 217 | Services.obs.notifyObservers(
|
| ... | ... | @@ -267,16 +279,14 @@ class InternetTest { |
| 267 | 279 | this.cancel();
|
| 268 | 280 | this._pending = true;
|
| 269 | 281 | |
| 270 | - console.log("TorConnect: starting the Internet test");
|
|
| 282 | + lazy.logger.info("Starting the Internet test");
|
|
| 271 | 283 | this._testAsync()
|
| 272 | 284 | .then(status => {
|
| 273 | 285 | this._pending = false;
|
| 274 | 286 | this._status = status.successful
|
| 275 | 287 | ? InternetStatus.Online
|
| 276 | 288 | : InternetStatus.Offline;
|
| 277 | - console.log(
|
|
| 278 | - `TorConnect: performed Internet test, outcome ${this._status}`
|
|
| 279 | - );
|
|
| 289 | + lazy.logger.info(`Performed Internet test, outcome ${this._status}`);
|
|
| 280 | 290 | this.onResult(this.status, status.date);
|
| 281 | 291 | })
|
| 282 | 292 | .catch(error => {
|
| ... | ... | @@ -305,7 +315,7 @@ class InternetTest { |
| 305 | 315 | await mrpc.init();
|
| 306 | 316 | status = await mrpc.testInternetConnection();
|
| 307 | 317 | } catch (err) {
|
| 308 | - console.error("Error while checking the Internet connection", err);
|
|
| 318 | + lazy.logger.error("Error while checking the Internet connection", err);
|
|
| 309 | 319 | error = err;
|
| 310 | 320 | } finally {
|
| 311 | 321 | mrpc.uninit();
|
| ... | ... | @@ -523,8 +533,8 @@ export const TorConnect = (() => { |
| 523 | 533 | // get "Building circuits: Establishing a Tor circuit failed".
|
| 524 | 534 | // TODO: Maybe move this logic deeper in the process to know
|
| 525 | 535 | // when to filter out such errors triggered by cancelling.
|
| 526 | - console.log(
|
|
| 527 | - `TorConnect: Post-cancel error => ${message}; ${details}`
|
|
| 536 | + lazy.logger.warn(
|
|
| 537 | + `Post-cancel error => ${message}; ${details}`
|
|
| 528 | 538 | );
|
| 529 | 539 | return;
|
| 530 | 540 | }
|
| ... | ... | @@ -628,7 +638,7 @@ export const TorConnect = (() => { |
| 628 | 638 | "vanilla",
|
| 629 | 639 | ]);
|
| 630 | 640 | } catch (err) {
|
| 631 | - console.error(
|
|
| 641 | + lazy.logger.error(
|
|
| 632 | 642 | "We did not get localized settings, and default settings failed as well",
|
| 633 | 643 | err
|
| 634 | 644 | );
|
| ... | ... | @@ -651,10 +661,19 @@ export const TorConnect = (() => { |
| 651 | 661 | }
|
| 652 | 662 | }
|
| 653 | 663 | |
| 664 | + const restoreOriginalSettings = async () => {
|
|
| 665 | + try {
|
|
| 666 | + await TorSettings.applySettings();
|
|
| 667 | + } catch (e) {
|
|
| 668 | + // We cannot do much if the original settings were bad or
|
|
| 669 | + // if the connection closed, so just report it in the
|
|
| 670 | + // console.
|
|
| 671 | + lazy.logger.warn("Failed to restore original settings.", e);
|
|
| 672 | + }
|
|
| 673 | + };
|
|
| 674 | + |
|
| 654 | 675 | // apply each of our settings and try to bootstrap with each
|
| 655 | 676 | try {
|
| 656 | - this.originalSettings = TorSettings.getSettings();
|
|
| 657 | - |
|
| 658 | 677 | for (const [
|
| 659 | 678 | index,
|
| 660 | 679 | currentSetting,
|
| ... | ... | @@ -664,14 +683,32 @@ export const TorConnect = (() => { |
| 664 | 683 | break;
|
| 665 | 684 | }
|
| 666 | 685 | |
| 667 | - console.log(
|
|
| 668 | - `TorConnect: Attempting Bootstrap with configuration ${
|
|
| 669 | - index + 1
|
|
| 670 | - }/${this.settings.length}`
|
|
| 686 | + lazy.logger.info(
|
|
| 687 | + `Attempting Bootstrap with configuration ${index + 1}/${
|
|
| 688 | + this.settings.length
|
|
| 689 | + }`
|
|
| 671 | 690 | );
|
| 672 | 691 | |
| 673 | - TorSettings.setSettings(currentSetting);
|
|
| 674 | - await TorSettings.applySettings();
|
|
| 692 | + // Send the new settings directly to the provider. We will
|
|
| 693 | + // save them only if the bootstrap succeeds.
|
|
| 694 | + // FIXME: We should somehow signal TorSettings users that we
|
|
| 695 | + // have set custom settings, and they should not apply
|
|
| 696 | + // theirs until we are done with trying ours.
|
|
| 697 | + // Otherwise, the new settings provided by the user while we
|
|
| 698 | + // were bootstrapping could be the ones that cause the
|
|
| 699 | + // bootstrap to succeed, but we overwrite them (unless we
|
|
| 700 | + // backup the original settings, and then save our new
|
|
| 701 | + // settings only if they have not changed).
|
|
| 702 | + // Another idea (maybe easier to implement) is to disable
|
|
| 703 | + // the settings UI while *any* bootstrap is going on.
|
|
| 704 | + // This is also documented in tor-browser#41921.
|
|
| 705 | + const provider = await lazy.TorProviderBuilder.build();
|
|
| 706 | + // We need to merge with old settings, in case the user is
|
|
| 707 | + // using a proxy or is behind a firewall.
|
|
| 708 | + await provider.writeSettings({
|
|
| 709 | + ...TorSettings.getSettings(),
|
|
| 710 | + ...currentSetting,
|
|
| 711 | + });
|
|
| 675 | 712 | |
| 676 | 713 | // build out our bootstrap request
|
| 677 | 714 | const tbr = new lazy.TorBootstrapRequest();
|
| ... | ... | @@ -679,8 +716,8 @@ export const TorConnect = (() => { |
| 679 | 716 | TorConnect._updateBootstrapStatus(progress, status);
|
| 680 | 717 | };
|
| 681 | 718 | tbr.onbootstraperror = (message, details) => {
|
| 682 | - console.log(
|
|
| 683 | - `TorConnect: Auto-Bootstrap error => ${message}; ${details}`
|
|
| 719 | + lazy.logger.error(
|
|
| 720 | + `Auto-Bootstrap error => ${message}; ${details}`
|
|
| 684 | 721 | );
|
| 685 | 722 | };
|
| 686 | 723 | |
| ... | ... | @@ -688,6 +725,7 @@ export const TorConnect = (() => { |
| 688 | 725 | this.on_transition = async nextState => {
|
| 689 | 726 | if (nextState === TorConnectState.Configuring) {
|
| 690 | 727 | await tbr.cancel();
|
| 728 | + await restoreOriginalSettings();
|
|
| 691 | 729 | }
|
| 692 | 730 | resolve();
|
| 693 | 731 | };
|
| ... | ... | @@ -695,23 +733,20 @@ export const TorConnect = (() => { |
| 695 | 733 | // begin bootstrap
|
| 696 | 734 | if (await tbr.bootstrap()) {
|
| 697 | 735 | // persist the current settings to preferences
|
| 736 | + TorSettings.setSettings(currentSetting);
|
|
| 698 | 737 | TorSettings.saveToPrefs();
|
| 738 | + await TorSettings.applySettings();
|
|
| 699 | 739 | TorConnect._changeState(TorConnectState.Bootstrapped);
|
| 700 | 740 | return;
|
| 701 | 741 | }
|
| 702 | 742 | }
|
| 703 | 743 | |
| 704 | - // bootstrapped failed for all potential settings, so reset daemon to use original
|
|
| 705 | - TorSettings.setSettings(this.originalSettings);
|
|
| 706 | - // The original settings should be good, so we save them to
|
|
| 707 | - // preferences before trying to apply them, as it might fail
|
|
| 708 | - // if the actual problem is with the connection to the control
|
|
| 709 | - // port.
|
|
| 710 | - // FIXME: We should handle this case in a better way.
|
|
| 711 | - TorSettings.saveToPrefs();
|
|
| 712 | - await TorSettings.applySettings();
|
|
| 713 | - |
|
| 714 | - // only explicitly change state here if something else has not transitioned us
|
|
| 744 | + // Bootstrap failed for all potential settings, so restore the
|
|
| 745 | + // original settings the provider.
|
|
| 746 | + await restoreOriginalSettings();
|
|
| 747 | + |
|
| 748 | + // Only explicitly change state here if something else has not
|
|
| 749 | + // transitioned us.
|
|
| 715 | 750 | if (!this.transitioning) {
|
| 716 | 751 | throw_error(
|
| 717 | 752 | TorStrings.torConnect.autoBootstrappingFailed,
|
| ... | ... | @@ -720,18 +755,8 @@ export const TorConnect = (() => { |
| 720 | 755 | }
|
| 721 | 756 | return;
|
| 722 | 757 | } catch (err) {
|
| 723 | - // restore original settings in case of error
|
|
| 724 | - try {
|
|
| 725 | - TorSettings.setSettings(this.originalSettings);
|
|
| 726 | - // As above
|
|
| 727 | - TorSettings.saveToPrefs();
|
|
| 728 | - await TorSettings.applySettings();
|
|
| 729 | - } catch (errRestore) {
|
|
| 730 | - console.log(
|
|
| 731 | - `TorConnect: Failed to restore original settings => ${errRestore}`
|
|
| 732 | - );
|
|
| 733 | - }
|
|
| 734 | - // throw to outer catch to transition us
|
|
| 758 | + await restoreOriginalSettings();
|
|
| 759 | + // throw to outer catch to transition us.
|
|
| 735 | 760 | throw err;
|
| 736 | 761 | }
|
| 737 | 762 | } catch (err) {
|
| ... | ... | @@ -748,8 +773,8 @@ export const TorConnect = (() => { |
| 748 | 773 | true
|
| 749 | 774 | );
|
| 750 | 775 | } else {
|
| 751 | - console.error(
|
|
| 752 | - "TorConnect: Received AutoBootstrapping error after transitioning",
|
|
| 776 | + lazy.logger.error(
|
|
| 777 | + "Received AutoBootstrapping error after transitioning",
|
|
| 753 | 778 | err
|
| 754 | 779 | );
|
| 755 | 780 | }
|
| ... | ... | @@ -793,8 +818,8 @@ export const TorConnect = (() => { |
| 793 | 818 | |
| 794 | 819 | TorConnect._errorMessage = errorMessage;
|
| 795 | 820 | TorConnect._errorDetails = errorDetails;
|
| 796 | - console.error(
|
|
| 797 | - `[TorConnect] Entering error state (${errorMessage}, ${errorDetails})`
|
|
| 821 | + lazy.logger.error(
|
|
| 822 | + `Entering error state (${errorMessage}, ${errorDetails})`
|
|
| 798 | 823 | );
|
| 799 | 824 | |
| 800 | 825 | Services.obs.notifyObservers(
|
| ... | ... | @@ -835,9 +860,7 @@ export const TorConnect = (() => { |
| 835 | 860 | );
|
| 836 | 861 | }
|
| 837 | 862 | |
| 838 | - console.log(
|
|
| 839 | - `TorConnect: Try transitioning from ${prevState} to ${newState}`
|
|
| 840 | - );
|
|
| 863 | + lazy.logger.trace(`Try transitioning from ${prevState} to ${newState}`);
|
|
| 841 | 864 | |
| 842 | 865 | // set our new state first so that state transitions can themselves trigger
|
| 843 | 866 | // a state transition
|
| ... | ... | @@ -851,8 +874,8 @@ export const TorConnect = (() => { |
| 851 | 874 | this._bootstrapProgress = progress;
|
| 852 | 875 | this._bootstrapStatus = status;
|
| 853 | 876 | |
| 854 | - console.log(
|
|
| 855 | - `TorConnect: Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`
|
|
| 877 | + lazy.logger.info(
|
|
| 878 | + `Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`
|
|
| 856 | 879 | );
|
| 857 | 880 | Services.obs.notifyObservers(
|
| 858 | 881 | {
|
| ... | ... | @@ -866,7 +889,7 @@ export const TorConnect = (() => { |
| 866 | 889 | |
| 867 | 890 | // init should be called by TorStartupService
|
| 868 | 891 | init() {
|
| 869 | - console.log("TorConnect: init()");
|
|
| 892 | + lazy.logger.debug("TorConnect.init()");
|
|
| 870 | 893 | this._callback(TorConnectState.Initial).begin();
|
| 871 | 894 | |
| 872 | 895 | if (!this.enabled) {
|
| ... | ... | @@ -875,9 +898,17 @@ export const TorConnect = (() => { |
| 875 | 898 | } else {
|
| 876 | 899 | let observeTopic = addTopic => {
|
| 877 | 900 | Services.obs.addObserver(this, addTopic);
|
| 878 | - console.log(`TorConnect: Observing topic '${addTopic}'`);
|
|
| 901 | + lazy.logger.debug(`Observing topic '${addTopic}'`);
|
|
| 879 | 902 | };
|
| 880 | 903 | |
| 904 | + // Wait for TorSettings, as we will need it.
|
|
| 905 | + // We will wait for a TorProvider only after TorSettings is ready,
|
|
| 906 | + // because the TorProviderBuilder initialization might not have finished
|
|
| 907 | + // at this point, and TorSettings initialization is a prerequisite for
|
|
| 908 | + // having a provider.
|
|
| 909 | + // So, we prefer initializing TorConnect as soon as possible, so that
|
|
| 910 | + // the UI will be able to detect it is in the Initializing state and act
|
|
| 911 | + // consequently.
|
|
| 881 | 912 | TorSettings.initializedPromise.then(() => this._settingsInitialized());
|
| 882 | 913 | |
| 883 | 914 | // register the Tor topics we always care about
|
| ... | ... | @@ -887,7 +918,7 @@ export const TorConnect = (() => { |
| 887 | 918 | },
|
| 888 | 919 | |
| 889 | 920 | async observe(subject, topic, data) {
|
| 890 | - console.log(`TorConnect: Observed ${topic}`);
|
|
| 921 | + lazy.logger.debug(`Observed ${topic}`);
|
|
| 891 | 922 | |
| 892 | 923 | switch (topic) {
|
| 893 | 924 | case TorTopics.LogHasWarnOrErr: {
|
| ... | ... | @@ -919,19 +950,25 @@ export const TorConnect = (() => { |
| 919 | 950 | }
|
| 920 | 951 | },
|
| 921 | 952 | |
| 922 | - _settingsInitialized() {
|
|
| 953 | + async _settingsInitialized() {
|
|
| 954 | + // TODO: Handle failures here, instead of the prompt to restart the
|
|
| 955 | + // daemon when it exits (tor-browser#21053, tor-browser#41921).
|
|
| 956 | + await lazy.TorProviderBuilder.build();
|
|
| 957 | + |
|
| 923 | 958 | // tor-browser#41907: This is only a workaround to avoid users being
|
| 924 | 959 | // bounced back to the initial panel without any explanation.
|
| 925 | 960 | // Longer term we should disable the clickable elements, or find a UX
|
| 926 | 961 | // to prevent this from happening (e.g., allow buttons to be clicked,
|
| 927 | 962 | // but show an intermediate starting state, or a message that tor is
|
| 928 | 963 | // starting while the butons are disabled, etc...).
|
| 964 | + // See also tor-browser#41921.
|
|
| 929 | 965 | if (this.state !== TorConnectState.Initial) {
|
| 930 | - console.warn(
|
|
| 931 | - "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification."
|
|
| 966 | + lazy.logger.warn(
|
|
| 967 | + "The TorProvider was built after the state had already changed."
|
|
| 932 | 968 | );
|
| 933 | 969 | return;
|
| 934 | 970 | }
|
| 971 | + lazy.logger.debug("The TorProvider is ready, changing state.");
|
|
| 935 | 972 | if (this.shouldQuickStart) {
|
| 936 | 973 | // Quickstart
|
| 937 | 974 | this._changeState(TorConnectState.Bootstrapping);
|
| ... | ... | @@ -1074,17 +1111,17 @@ export const TorConnect = (() => { |
| 1074 | 1111 | */
|
| 1075 | 1112 | |
| 1076 | 1113 | beginBootstrap() {
|
| 1077 | - console.log("TorConnect: beginBootstrap()");
|
|
| 1114 | + lazy.logger.debug("TorConnect.beginBootstrap()");
|
|
| 1078 | 1115 | this._changeState(TorConnectState.Bootstrapping);
|
| 1079 | 1116 | },
|
| 1080 | 1117 | |
| 1081 | 1118 | cancelBootstrap() {
|
| 1082 | - console.log("TorConnect: cancelBootstrap()");
|
|
| 1119 | + lazy.logger.debug("TorConnect.cancelBootstrap()");
|
|
| 1083 | 1120 | this._changeState(TorConnectState.Configuring);
|
| 1084 | 1121 | },
|
| 1085 | 1122 | |
| 1086 | 1123 | beginAutoBootstrap(countryCode) {
|
| 1087 | - console.log("TorConnect: beginAutoBootstrap()");
|
|
| 1124 | + lazy.logger.debug("TorConnect.beginAutoBootstrap()");
|
|
| 1088 | 1125 | this._changeState(TorConnectState.AutoBootstrapping, countryCode);
|
| 1089 | 1126 | },
|
| 1090 | 1127 | |
| ... | ... | @@ -1154,7 +1191,10 @@ export const TorConnect = (() => { |
| 1154 | 1191 | await mrpc.init();
|
| 1155 | 1192 | this._countryCodes = await mrpc.circumvention_countries();
|
| 1156 | 1193 | } catch (err) {
|
| 1157 | - console.log("An error occurred while fetching country codes", err);
|
|
| 1194 | + lazy.logger.error(
|
|
| 1195 | + "An error occurred while fetching country codes",
|
|
| 1196 | + err
|
|
| 1197 | + );
|
|
| 1158 | 1198 | } finally {
|
| 1159 | 1199 | mrpc.uninit();
|
| 1160 | 1200 | }
|
| ... | ... | @@ -1187,8 +1227,8 @@ export const TorConnect = (() => { |
| 1187 | 1227 | uriArray = uriVariant;
|
| 1188 | 1228 | } else {
|
| 1189 | 1229 | // about:tor as safe fallback
|
| 1190 | - console.error(
|
|
| 1191 | - `TorConnect: received unknown variant '${JSON.stringify(uriVariant)}'`
|
|
| 1230 | + lazy.logger.error(
|
|
| 1231 | + `Received unknown variant '${JSON.stringify(uriVariant)}'`
|
|
| 1192 | 1232 | );
|
| 1193 | 1233 | uriArray = ["about:tor"];
|
| 1194 | 1234 | }
|
| ... | ... | @@ -1209,9 +1249,7 @@ export const TorConnect = (() => { |
| 1209 | 1249 | // which redirect after bootstrapping
|
| 1210 | 1250 | getURIsToLoad(uriVariant) {
|
| 1211 | 1251 | const uris = this.fixupURIs(uriVariant);
|
| 1212 | - console.log(
|
|
| 1213 | - `TorConnect: Will load after bootstrap => [${uris.join(", ")}]`
|
|
| 1214 | - );
|
|
| 1252 | + lazy.logger.debug(`Will load after bootstrap => [${uris.join(", ")}]`);
|
|
| 1215 | 1253 | return uris.map(uri => this.getRedirectURL(uri));
|
| 1216 | 1254 | },
|
| 1217 | 1255 | };
|
| ... | ... | @@ -6,10 +6,9 @@ const lazy = {}; |
| 6 | 6 | |
| 7 | 7 | ChromeUtils.defineESModuleGetters(lazy, {
|
| 8 | 8 | TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
|
| 9 | - TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
|
| 10 | - TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
|
| 11 | 9 | Lox: "resource://gre/modules/Lox.sys.mjs",
|
| 12 | 10 | TorParsers: "resource://gre/modules/TorParsers.sys.mjs",
|
| 11 | + TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
|
|
| 13 | 12 | });
|
| 14 | 13 | |
| 15 | 14 | ChromeUtils.defineLazyGetter(lazy, "logger", () => {
|
| ... | ... | @@ -71,20 +70,6 @@ const TorSettingsPrefs = Object.freeze({ |
| 71 | 70 | },
|
| 72 | 71 | });
|
| 73 | 72 | |
| 74 | -/* Config Keys used to configure tor daemon */
|
|
| 75 | -const TorConfigKeys = Object.freeze({
|
|
| 76 | - useBridges: "UseBridges",
|
|
| 77 | - bridgeList: "Bridge",
|
|
| 78 | - socks4Proxy: "Socks4Proxy",
|
|
| 79 | - socks5Proxy: "Socks5Proxy",
|
|
| 80 | - socks5ProxyUsername: "Socks5ProxyUsername",
|
|
| 81 | - socks5ProxyPassword: "Socks5ProxyPassword",
|
|
| 82 | - httpsProxy: "HTTPSProxy",
|
|
| 83 | - httpsProxyAuthenticator: "HTTPSProxyAuthenticator",
|
|
| 84 | - reachableAddresses: "ReachableAddresses",
|
|
| 85 | - clientTransportPlugin: "ClientTransportPlugin",
|
|
| 86 | -});
|
|
| 87 | - |
|
| 88 | 73 | export const TorBridgeSource = Object.freeze({
|
| 89 | 74 | Invalid: -1,
|
| 90 | 75 | BuiltIn: 0,
|
| ... | ... | @@ -322,7 +307,7 @@ class TorSettingsImpl { |
| 322 | 307 | if (!val) {
|
| 323 | 308 | return;
|
| 324 | 309 | }
|
| 325 | - const bridgeStrings = this.#getBuiltinBridges(val);
|
|
| 310 | + const bridgeStrings = this.getBuiltinBridges(val);
|
|
| 326 | 311 | if (bridgeStrings.length) {
|
| 327 | 312 | this.bridges.bridge_strings = bridgeStrings;
|
| 328 | 313 | return;
|
| ... | ... | @@ -659,14 +644,17 @@ class TorSettingsImpl { |
| 659 | 644 | * @param {string} pt The pluggable transport to return the lines for
|
| 660 | 645 | * @returns {string[]} The bridge lines in random order
|
| 661 | 646 | */
|
| 662 | - #getBuiltinBridges(pt) {
|
|
| 647 | + getBuiltinBridges(pt) {
|
|
| 648 | + if (!this.#allowUninitialized) {
|
|
| 649 | + this.#checkIfInitialized();
|
|
| 650 | + }
|
|
| 663 | 651 | // Shuffle so that Tor Browser users do not all try the built-in bridges in
|
| 664 | 652 | // the same order.
|
| 665 | 653 | return arrayShuffle(this.#builtinBridges[pt] ?? []);
|
| 666 | 654 | }
|
| 667 | 655 | |
| 668 | 656 | /**
|
| 669 | - * Load or init our settings, and register observers.
|
|
| 657 | + * Load or init our settings.
|
|
| 670 | 658 | */
|
| 671 | 659 | async init() {
|
| 672 | 660 | if (this.#initialized) {
|
| ... | ... | @@ -677,6 +665,7 @@ class TorSettingsImpl { |
| 677 | 665 | await this.#initInternal();
|
| 678 | 666 | this.#initialized = true;
|
| 679 | 667 | this.#initComplete();
|
| 668 | + Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
|
|
| 680 | 669 | } catch (e) {
|
| 681 | 670 | this.#initFailed(e);
|
| 682 | 671 | throw e;
|
| ... | ... | @@ -698,45 +687,35 @@ class TorSettingsImpl { |
| 698 | 687 | lazy.logger.error("Could not load the built-in PT config.", e);
|
| 699 | 688 | }
|
| 700 | 689 | |
| 701 | - // Initialize this before loading from prefs because we need Lox initialized before
|
|
| 702 | - // any calls to Lox.getBridges()
|
|
| 690 | + // Initialize this before loading from prefs because we need Lox initialized
|
|
| 691 | + // before any calls to Lox.getBridges().
|
|
| 703 | 692 | try {
|
| 704 | 693 | await lazy.Lox.init();
|
| 705 | 694 | } catch (e) {
|
| 706 | 695 | lazy.logger.error("Could not initialize Lox.", e.type);
|
| 707 | 696 | }
|
| 708 | 697 | |
| 709 | - // TODO: We could use a shared promise, and wait for it to be fullfilled
|
|
| 710 | - // instead of Service.obs.
|
|
| 711 | - if (lazy.TorLauncherUtil.shouldStartAndOwnTor) {
|
|
| 712 | - // if the settings branch exists, load settings from prefs
|
|
| 713 | - if (Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)) {
|
|
| 714 | - // Do not want notifications for initially loaded prefs.
|
|
| 715 | - this.freezeNotifications();
|
|
| 716 | - try {
|
|
| 717 | - this.#allowUninitialized = true;
|
|
| 718 | - this.#loadFromPrefs();
|
|
| 719 | - } finally {
|
|
| 720 | - this.#allowUninitialized = false;
|
|
| 721 | - this.#notificationQueue.clear();
|
|
| 722 | - this.thawNotifications();
|
|
| 723 | - }
|
|
| 724 | - }
|
|
| 698 | + if (
|
|
| 699 | + lazy.TorLauncherUtil.shouldStartAndOwnTor &&
|
|
| 700 | + Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)
|
|
| 701 | + ) {
|
|
| 702 | + // Do not want notifications for initially loaded prefs.
|
|
| 703 | + this.freezeNotifications();
|
|
| 725 | 704 | try {
|
| 726 | - const provider = await lazy.TorProviderBuilder.build();
|
|
| 727 | - if (provider.isRunning) {
|
|
| 728 | - this.#handleProcessReady();
|
|
| 729 | - // No need to add an observer to call this again.
|
|
| 730 | - return;
|
|
| 731 | - }
|
|
| 732 | - } catch {}
|
|
| 733 | - |
|
| 734 | - Services.obs.addObserver(this, lazy.TorProviderTopics.ProcessIsReady);
|
|
| 705 | + this.#allowUninitialized = true;
|
|
| 706 | + this.#loadFromPrefs();
|
|
| 707 | + } finally {
|
|
| 708 | + this.#allowUninitialized = false;
|
|
| 709 | + this.#notificationQueue.clear();
|
|
| 710 | + this.thawNotifications();
|
|
| 711 | + }
|
|
| 735 | 712 | }
|
| 713 | + |
|
| 714 | + lazy.logger.info("Ready");
|
|
| 736 | 715 | }
|
| 737 | 716 | |
| 738 | 717 | /**
|
| 739 | - * Unload or uninit our settings, and unregister observers.
|
|
| 718 | + * Unload or uninit our settings.
|
|
| 740 | 719 | */
|
| 741 | 720 | async uninit() {
|
| 742 | 721 | await lazy.Lox.uninit();
|
| ... | ... | @@ -764,34 +743,6 @@ class TorSettingsImpl { |
| 764 | 743 | return this.#initialized;
|
| 765 | 744 | }
|
| 766 | 745 | |
| 767 | - /**
|
|
| 768 | - * Wait for relevant life-cycle events to apply saved settings.
|
|
| 769 | - */
|
|
| 770 | - async observe(subject, topic, data) {
|
|
| 771 | - lazy.logger.debug(`Observed ${topic}`);
|
|
| 772 | - |
|
| 773 | - switch (topic) {
|
|
| 774 | - case lazy.TorProviderTopics.ProcessIsReady:
|
|
| 775 | - Services.obs.removeObserver(
|
|
| 776 | - this,
|
|
| 777 | - lazy.TorProviderTopics.ProcessIsReady
|
|
| 778 | - );
|
|
| 779 | - await this.#handleProcessReady();
|
|
| 780 | - break;
|
|
| 781 | - }
|
|
| 782 | - }
|
|
| 783 | - |
|
| 784 | - /**
|
|
| 785 | - * Apply the settings once the tor provider is ready and notify any observer
|
|
| 786 | - * that the settings can be used.
|
|
| 787 | - */
|
|
| 788 | - async #handleProcessReady() {
|
|
| 789 | - // push down settings to tor
|
|
| 790 | - await this.#applySettings(true);
|
|
| 791 | - lazy.logger.info("Ready");
|
|
| 792 | - Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
|
|
| 793 | - }
|
|
| 794 | - |
|
| 795 | 746 | /**
|
| 796 | 747 | * Load our settings from prefs.
|
| 797 | 748 | */
|
| ... | ... | @@ -972,85 +923,14 @@ class TorSettingsImpl { |
| 972 | 923 | |
| 973 | 924 | /**
|
| 974 | 925 | * Push our settings down to the tor provider.
|
| 926 | + *
|
|
| 927 | + * Even though this introduces a circular depdency, it makes the API nicer for
|
|
| 928 | + * frontend consumers.
|
|
| 975 | 929 | */
|
| 976 | 930 | async applySettings() {
|
| 977 | 931 | this.#checkIfInitialized();
|
| 978 | - return this.#applySettings(false);
|
|
| 979 | - }
|
|
| 980 | - |
|
| 981 | - /**
|
|
| 982 | - * Internal implementation of applySettings that does not check if we are
|
|
| 983 | - * initialized.
|
|
| 984 | - */
|
|
| 985 | - async #applySettings(allowUninitialized) {
|
|
| 986 | - lazy.logger.debug("#applySettings()");
|
|
| 987 | - |
|
| 988 | - this.#cleanupSettings();
|
|
| 989 | - |
|
| 990 | - const settingsMap = new Map();
|
|
| 991 | - |
|
| 992 | - // #applySettings can be called only when #allowUninitialized is false
|
|
| 993 | - this.#allowUninitialized = allowUninitialized;
|
|
| 994 | - |
|
| 995 | - try {
|
|
| 996 | - /* Bridges */
|
|
| 997 | - const haveBridges =
|
|
| 998 | - this.bridges.enabled && !!this.bridges.bridge_strings.length;
|
|
| 999 | - settingsMap.set(TorConfigKeys.useBridges, haveBridges);
|
|
| 1000 | - if (haveBridges) {
|
|
| 1001 | - settingsMap.set(TorConfigKeys.bridgeList, this.bridges.bridge_strings);
|
|
| 1002 | - } else {
|
|
| 1003 | - settingsMap.set(TorConfigKeys.bridgeList, null);
|
|
| 1004 | - }
|
|
| 1005 | - |
|
| 1006 | - /* Proxy */
|
|
| 1007 | - settingsMap.set(TorConfigKeys.socks4Proxy, null);
|
|
| 1008 | - settingsMap.set(TorConfigKeys.socks5Proxy, null);
|
|
| 1009 | - settingsMap.set(TorConfigKeys.socks5ProxyUsername, null);
|
|
| 1010 | - settingsMap.set(TorConfigKeys.socks5ProxyPassword, null);
|
|
| 1011 | - settingsMap.set(TorConfigKeys.httpsProxy, null);
|
|
| 1012 | - settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null);
|
|
| 1013 | - if (this.proxy.enabled) {
|
|
| 1014 | - const address = this.proxy.address;
|
|
| 1015 | - const port = this.proxy.port;
|
|
| 1016 | - const username = this.proxy.username;
|
|
| 1017 | - const password = this.proxy.password;
|
|
| 1018 | - |
|
| 1019 | - switch (this.proxy.type) {
|
|
| 1020 | - case TorProxyType.Socks4:
|
|
| 1021 | - settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`);
|
|
| 1022 | - break;
|
|
| 1023 | - case TorProxyType.Socks5:
|
|
| 1024 | - settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`);
|
|
| 1025 | - settingsMap.set(TorConfigKeys.socks5ProxyUsername, username);
|
|
| 1026 | - settingsMap.set(TorConfigKeys.socks5ProxyPassword, password);
|
|
| 1027 | - break;
|
|
| 1028 | - case TorProxyType.HTTPS:
|
|
| 1029 | - settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`);
|
|
| 1030 | - settingsMap.set(
|
|
| 1031 | - TorConfigKeys.httpsProxyAuthenticator,
|
|
| 1032 | - `${username}:${password}`
|
|
| 1033 | - );
|
|
| 1034 | - break;
|
|
| 1035 | - }
|
|
| 1036 | - }
|
|
| 1037 | - |
|
| 1038 | - /* Firewall */
|
|
| 1039 | - if (this.firewall.enabled) {
|
|
| 1040 | - const reachableAddresses = this.firewall.allowed_ports
|
|
| 1041 | - .map(port => `*:${port}`)
|
|
| 1042 | - .join(",");
|
|
| 1043 | - settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses);
|
|
| 1044 | - } else {
|
|
| 1045 | - settingsMap.set(TorConfigKeys.reachableAddresses, null);
|
|
| 1046 | - }
|
|
| 1047 | - } finally {
|
|
| 1048 | - this.#allowUninitialized = false;
|
|
| 1049 | - }
|
|
| 1050 | - |
|
| 1051 | - /* Push to Tor */
|
|
| 1052 | 932 | const provider = await lazy.TorProviderBuilder.build();
|
| 1053 | - await provider.writeSettings(settingsMap);
|
|
| 933 | + await provider.writeSettings(this.getSettings());
|
|
| 1054 | 934 | }
|
| 1055 | 935 | |
| 1056 | 936 | /**
|