Pier Angelo Vendrame pushed to branch tor-browser-128.6.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits: 1ad717fe by Henry Wilkes at 2025-01-21T14:56:40+00:00 fixup! TB 40933: Add tor-launcher functionality
TB 41921: Ensure shouldStartAndOwnTor is constant per-session.
TorConnect and TorSettings `enabled` properties depend on this value, and shouldn't change per session.
- - - - - 8ae53510 by Henry Wilkes at 2025-01-21T14:56:41+00:00 fixup! TB 40597: Implement TorSettings module
TB 41921: Tighten up TorSettings.
We ensure TorSettings is enabled before certain operations.
Also tidy up uninit to account for early calls (before init completes) or repeat calls.
Also stop using "torbrowser.settings.enabled" preference, and read from the preferences for the first run.
Also make TorSettings.initailizedPromise read-only.
- - - - - a0c13700 by Henry Wilkes at 2025-01-21T14:56:41+00:00 fixup! TB 40562: Added Tor Browser preferences to 000-tor-browser.js
TB 41921: Set default TorSetting setting values in 000-tor-browser.js.
- - - - - 7a98943f by Henry Wilkes at 2025-01-21T15:00:22+00:00 fixup! TB 41435: Add a Tor Browser migration function
TB 41921: Clear out unused "torbrowser.settings.enabled" preference.
- - - - -
4 changed files:
- browser/app/profile/000-tor-browser.js - browser/components/BrowserGlue.sys.mjs - toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs - toolkit/modules/TorSettings.sys.mjs
Changes:
===================================== browser/app/profile/000-tor-browser.js ===================================== @@ -61,6 +61,31 @@ pref("browser.startup.homepage", "about:tor"); // tor-browser#40701: Add new download warning pref("browser.download.showTorWarning", true);
+ +// Tor connection setting preferences. + +pref("torbrowser.settings.quickstart.enabled", false); +pref("torbrowser.settings.bridges.enabled", false); +// TorBridgeSource. Initially TorBridgeSource.Invalid = -1. +pref("torbrowser.settings.bridges.source", -1); +pref("torbrowser.settings.bridges.lox_id", ""); +// obfs4|meek-azure|snowflake|etc. +pref("torbrowser.settings.bridges.builtin_type", ""); +// torbrowser.settings.bridges.bridge_strings.0 +// torbrowser.settings.bridges.bridge_strings.1 +// etc hold the bridge lines. +pref("torbrowser.settings.proxy.enabled", false); +// TorProxyType. Initially TorProxyType.Invalid = -1. +pref("torbrowser.settings.proxy.type", -1); +pref("torbrowser.settings.proxy.address", ""); +pref("torbrowser.settings.proxy.port", 0); +pref("torbrowser.settings.proxy.username", ""); +pref("torbrowser.settings.proxy.password", ""); +pref("torbrowser.settings.firewall.enabled", false); +// comma-delimited list of port numbers. +pref("torbrowser.settings.firewall.allowed_ports", ""); + + // This pref specifies an ad-hoc "version" for various pref update hacks we need to do pref("extensions.torbutton.pref_fixup_version", 0);
===================================== browser/components/BrowserGlue.sys.mjs ===================================== @@ -4822,7 +4822,9 @@ BrowserGlue.prototype = { // YouTube search engines (tor-browser#41835). // Version 5: Tor Browser 14.0a5: Clear user preference for CFR settings // since we hid the UI (tor-browser#43118). - const TBB_MIGRATION_VERSION = 5; + // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is + // no longer used (tor-browser#41921). + const TBB_MIGRATION_VERSION = 6; const MIGRATION_PREF = "torbrowser.migration.version";
// If we decide to force updating users to pass through any version @@ -4904,6 +4906,10 @@ BrowserGlue.prototype = { } }
+ if (currentVersion < 6) { + Services.prefs.clearUserPref("torbrowser.settings.enabled"); + } + Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION); },
===================================== toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs ===================================== @@ -17,8 +17,6 @@ const kPropBundleURI = "chrome://torbutton/locale/torlauncher.properties"; const kPropNamePrefix = "torlauncher."; const kIPCDirPrefName = "extensions.torlauncher.tmp_ipc_dir";
-let gStringBundle = null; - /** * This class allows to lookup for the paths of the various files that are * needed or can be used with the tor daemon, such as its configuration, the @@ -332,7 +330,7 @@ class TorFile { } }
-export const TorLauncherUtil = Object.freeze({ +export const TorLauncherUtil = { get isAndroid() { return Services.appinfo.OS === "Android"; }, @@ -417,6 +415,8 @@ export const TorLauncherUtil = Object.freeze({ return this.showConfirm(null, s, defaultBtnLabel, cancelBtnLabel); },
+ _stringBundle: null, + // Localized Strings // TODO: Switch to fluent also these ones.
@@ -425,6 +425,9 @@ export const TorLauncherUtil = Object.freeze({ if (!aStringName) { return aStringName; } + if (!this._stringBundle) { + this._stringBundle = Services.strings.createBundle(kPropBundleURI); + } try { const key = kPropNamePrefix + aStringName; return this._stringBundle.GetStringFromName(key); @@ -587,7 +590,12 @@ export const TorLauncherUtil = Object.freeze({ Services.prefs.savePrefFile(null); },
- get shouldStartAndOwnTor() { + /** + * Determine the current value for whether we should start and own Tor. + * + * @returns {boolean} Whether we should start and own Tor. + */ + _getShouldStartAndOwnTor() { const kPrefStartTor = "extensions.torlauncher.start_tor"; try { const kBrowserToolboxPort = "MOZ_BROWSER_TOOLBOX_PORT"; @@ -610,6 +618,29 @@ export const TorLauncherUtil = Object.freeze({ return Services.prefs.getBoolPref(kPrefStartTor, true); },
+ /** + * Cached value for shouldStartAndOwnTor, or `null` if not yet initialised. + * + * @type {boolean} + */ + _shouldStartAndOwnTor: null, + + /** + * Whether we should start and own Tor. + * + * The value should be constant per-session. + * + * @type {boolean} + */ + get shouldStartAndOwnTor() { + // Do not want this value to change within the same session, so always used + // the cached valued if it is available. + if (this._shouldStartAndOwnTor === null) { + this._shouldStartAndOwnTor = this._getShouldStartAndOwnTor(); + } + return this._shouldStartAndOwnTor; + }, + get shouldShowNetworkSettings() { try { const kEnvForceShowNetConfig = "TOR_FORCE_NET_CONFIG"; @@ -668,11 +699,4 @@ export const TorLauncherUtil = Object.freeze({ console.warn("Could not remove the IPC directory", e); } }, - - get _stringBundle() { - if (!gStringBundle) { - gStringBundle = Services.strings.createBundle(kPropBundleURI); - } - return gStringBundle; - }, -}); +};
===================================== toolkit/modules/TorSettings.sys.mjs ===================================== @@ -27,8 +27,6 @@ export const TorSettingsTopics = Object.freeze({
/* Prefs used to store settings in TorBrowser prefs */ const TorSettingsPrefs = Object.freeze({ - /* bool: are we pulling tor settings from the preferences */ - enabled: "torbrowser.settings.enabled", quickstart: { /* bool: does tor connect automatically on launch */ enabled: "torbrowser.settings.quickstart.enabled", @@ -245,6 +243,13 @@ class TorSettingsImpl { */ #builtinBridges = {};
+ /** + * A promise that resolves once we are initialized, or throws if there was an + * initialization error. + * + * @type {Promise} + */ + #initializedPromise; /** * Resolve callback of the initializedPromise. */ @@ -261,8 +266,29 @@ class TorSettingsImpl { */ #initialized = false;
+ /** + * Whether uninit cleanup has been called. + * + * @type {boolean} + */ + #uninitCalled = false; + + /** + * Whether Lox was initialized. + * + * @type {boolean} + */ + #initializedLox = false; + + /** + * Whether observers were initialized. + * + * @type {boolean} + */ + #initializedObservers = false; + constructor() { - this.initializedPromise = new Promise((resolve, reject) => { + this.#initializedPromise = new Promise((resolve, reject) => { this.#initComplete = resolve; this.#initFailed = reject; }); @@ -378,12 +404,22 @@ class TorSettingsImpl { return this.#builtinBridges[pt] ?? []; }
+ /** + * Whether this module is enabled. + * + * @type {boolean} + */ + get enabled() { + return lazy.TorLauncherUtil.shouldStartAndOwnTor; + } + /** * Load or init our settings. */ async init() { if (this.#initialized) { lazy.logger.warn("Called init twice."); + await this.#initializedPromise; return; } try { @@ -402,6 +438,11 @@ class TorSettingsImpl { * it easier to update initializatedPromise. */ async #initInternal() { + if (!this.enabled || this.#uninitCalled) { + // Nothing to do. + return; + } + try { const req = await fetch("chrome://global/content/pt_config.json"); const config = await req.json(); @@ -419,26 +460,37 @@ class TorSettingsImpl { lazy.logger.error("Could not load the built-in PT config.", e); }
+ // `uninit` may have been called whilst we awaited pt_config. + if (this.#uninitCalled) { + lazy.logger.warn("unint was called before init completed."); + return; + } + // Initialize this before loading from prefs because we need Lox initialized // before any calls to Lox.getBridges(). if (!lazy.TorLauncherUtil.isAndroid) { try { + // Set as initialized before calling to ensure it is cleaned up by our + // `uninit` method. + this.#initializedLox = true; await lazy.Lox.init(); } catch (e) { lazy.logger.error("Could not initialize Lox.", e); } }
- if ( - lazy.TorLauncherUtil.shouldStartAndOwnTor && - Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false) - ) { - this.#loadFromPrefs(); - // We do not pass on the loaded settings to the TorProvider yet. Instead - // TorProvider will ask for these once it has initialised. + // `uninit` may have been called whilst we awaited Lox.init. + if (this.#uninitCalled) { + lazy.logger.warn("unint was called before init completed."); + return; }
+ this.#loadFromPrefs(); + // We do not pass on the loaded settings to the TorProvider yet. Instead + // TorProvider will ask for these once it has initialised. + Services.obs.addObserver(this, lazy.LoxTopics.UpdateBridges); + this.#initializedObservers = true;
lazy.logger.info("Ready"); } @@ -447,8 +499,22 @@ class TorSettingsImpl { * Unload or uninit our settings. */ async uninit() { - Services.obs.removeObserver(this, lazy.LoxTopics.UpdateBridges); - await lazy.Lox.uninit(); + if (this.#uninitCalled) { + lazy.logger.warn("Called uninit twice"); + return; + } + + this.#uninitCalled = true; + // NOTE: We do not reset #initialized to false because we want it to remain + // in place for external callers, and we do not want `#initInternal` to be + // re-entered. + + if (this.#initializedObservers) { + Services.obs.removeObserver(this, lazy.LoxTopics.UpdateBridges); + } + if (this.#initializedLox) { + await lazy.Lox.uninit(); + } }
observe(subject, topic) { @@ -473,10 +539,13 @@ class TorSettingsImpl { }
/** - * Check whether the object has been successfully initialized, and throw if - * it has not. + * Check whether the module is enabled and successfully initialized, and throw + * if it is not. */ #checkIfInitialized() { + if (!this.enabled) { + throw new Error("TorSettings is not enabled"); + } if (!this.#initialized) { lazy.logger.trace("Not initialized code path."); throw new Error( @@ -494,6 +563,16 @@ class TorSettingsImpl { return this.#initialized; }
+ /** + * A promise that resolves once we are initialized, or throws if there was an + * initialization error. + * + * @type {Promise} + */ + get initializedPromise() { + return this.#initializedPromise; + } + /** * Load our settings from prefs. */ @@ -701,9 +780,6 @@ class TorSettingsImpl { } else { Services.prefs.clearUserPref(TorSettingsPrefs.firewall.allowed_ports); } - - // all tor settings now stored in prefs :) - Services.prefs.setBoolPref(TorSettingsPrefs.enabled, true); }
/**
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/06cbcd5...
tor-commits@lists.torproject.org