Pier Angelo Vendrame pushed to branch tor-browser-128.6.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits: 6571ac7b by Henry Wilkes at 2025-01-21T14:15:40+00:00 fixup! TB 40933: Add tor-launcher functionality
TB 41921: Move prompt_at_startup preference from TorProvider to TorConnect only.
- - - - - fa81e56c by Henry Wilkes at 2025-01-21T14:15:40+00:00 fixup! TB 40597: Implement TorSettings module
TB 41921: Move prompt_at_startup pref from TorProvider to TorConnect only.
This simplifies the logic, where we set the preference any time we have a bootstrap error and clear it when we are bootstrapped.
- - - - - 093e9483 by Henry Wilkes at 2025-01-21T14:15:41+00:00 fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
TB 41921: Move flushSettings call to TorSettings.
The call in connectionPane will not necessarily run when the preference tab is closed, nor will it trigger for bridges added through auto-bootstrapping.
- - - - - b50c1c9c by Henry Wilkes at 2025-01-21T14:15:42+00:00 fixup! TB 40597: Implement TorSettings module
TB 41921: Flush TorSettings settings every time they are saved.
- - - - - 06cbcd5d by Henry Wilkes at 2025-01-21T14:15:43+00:00 fixup! TB 40933: Add tor-launcher functionality
TB 41921: Add a NOTE for future development ensuring that writeSettings is not subject to any races between sequential calls.
- - - - -
5 changed files:
- browser/components/torpreferences/content/connectionPane.js - toolkit/components/tor-launcher/TorControlPort.sys.mjs - toolkit/components/tor-launcher/TorProvider.sys.mjs - toolkit/modules/TorConnect.sys.mjs - toolkit/modules/TorSettings.sys.mjs
Changes:
===================================== browser/components/torpreferences/content/connectionPane.js ===================================== @@ -2545,19 +2545,6 @@ const gConnectionPane = (function () {
// populate xul with strings and cache the relevant elements _populateXUL() { - // saves tor settings to disk when navigate away from about:preferences - window.addEventListener("blur", async () => { - try { - // Build a new provider each time because this might be called also - // when closing the browser (if about:preferences was open), maybe - // when the provider was already uninitialized. - const provider = await TorProviderBuilder.build(); - provider.flushSettings(); - } catch (e) { - console.warn("Could not save the tor settings.", e); - } - }); - // Quickstart this._enableQuickstartCheckbox = document.getElementById( "torPreferences-quickstart-toggle"
===================================== toolkit/components/tor-launcher/TorControlPort.sys.mjs ===================================== @@ -364,6 +364,9 @@ export class TorController { /** * The commands that need to be run or receive a response. * + * NOTE: This must be in the order with the last requested command at the end + * of the queue. + * * @type {Command[]} */ #commandQueue = []; @@ -947,6 +950,10 @@ export class TorController { * values will be automatically unrolled. */ async setConf(values) { + // NOTE: This is an async method. It must ensure that sequential calls to + // this method do not race against each other. I.e. the last call to this + // method must always be the last in #commandQueue. Otherwise a delayed + // earlier call could overwrite the configuration of a later call. const args = values .flatMap(([key, value]) => { if (value === undefined || value === null) {
===================================== toolkit/components/tor-launcher/TorProvider.sys.mjs ===================================== @@ -70,7 +70,6 @@ const Preferences = Object.freeze({ ControlHost: "extensions.torlauncher.control_host", ControlPort: "extensions.torlauncher.control_port", MaxLogEntries: "extensions.torlauncher.max_tor_log_entries", - PromptAtStartup: "extensions.torlauncher.prompt_at_startup", });
/* Config Keys used to configure tor daemon */ @@ -335,6 +334,15 @@ export class TorProvider { }
logger.debug("Mapped settings object", settings, torSettings); + + // Send settings to the tor process. + // NOTE: Since everything up to this point has been non-async, the order in + // which TorProvider.writeSettings is called should match the order in which + // the configuration is passed onto setConf. In turn, TorControlPort.setConf + // should similarly ensure that the configuration reaches the tor process in + // the same order. + // In particular, we do not want a race where an earlier call to + // TorProvider.writeSettings can be delayed and override a later call. await this.#controller.setConf(Array.from(torSettings)); }
@@ -962,11 +970,6 @@ export class TorProvider {
if (statusObj.PROGRESS === 100) { this.#isBootstrapDone = true; - try { - Services.prefs.setBoolPref(Preferences.PromptAtStartup, false); - } catch (e) { - logger.warn(`Cannot set ${Preferences.PromptAtStartup}`, e); - } return; }
@@ -988,11 +991,6 @@ export class TorProvider { * @param {object} statusObj The bootstrap status object with the error */ #notifyBootstrapError(statusObj) { - try { - Services.prefs.setBoolPref(Preferences.PromptAtStartup, true); - } catch (e) { - logger.warn(`Cannot set ${Preferences.PromptAtStartup}`, e); - } logger.error("Tor bootstrap error", statusObj);
if (
===================================== toolkit/modules/TorConnect.sys.mjs ===================================== @@ -16,15 +16,12 @@ ChromeUtils.defineESModuleGetters(lazy, { TorSettings: "resource://gre/modules/TorSettings.sys.mjs", });
-/* Relevant prefs used by tor-launcher */ -const TorLauncherPrefs = Object.freeze({ - prompt_at_startup: "extensions.torlauncher.prompt_at_startup", -}); - const TorConnectPrefs = Object.freeze({ censorship_level: "torbrowser.debug.censorship_level", allow_internet_test: "torbrowser.bootstrap.allow_internet_test", log_level: "torbrowser.bootstrap.log_level", + /* prompt_at_startup now controls whether the quickstart can trigger. */ + prompt_at_startup: "extensions.torlauncher.prompt_at_startup", });
export const TorConnectState = Object.freeze({ @@ -1050,7 +1047,7 @@ export const TorConnect = { lazy.logger.info("Starting again since the tor process exited"); // Treat a failure as a possibly broken configuration. // So, prevent quickstart at the next start. - Services.prefs.setBoolPref(TorLauncherPrefs.prompt_at_startup, true); + Services.prefs.setBoolPref(TorConnectPrefs.prompt_at_startup, true); this._makeStageRequest(TorConnectStage.Start, true); break; default: @@ -1171,7 +1168,7 @@ export const TorConnect = { return ( lazy.TorSettings.quickstart.enabled && // and the previous bootstrap attempt must have succeeded - !Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true) + !Services.prefs.getBoolPref(TorConnectPrefs.prompt_at_startup, true) ); },
@@ -1451,6 +1448,8 @@ export const TorConnect = { this._tryAgain = false; this._potentiallyBlocked = false; this._errorDetails = null; + // Re-enable quickstart for future sessions. + Services.prefs.setBoolPref(TorConnectPrefs.prompt_at_startup, false);
if (requestedStage) { lazy.logger.warn( @@ -1491,6 +1490,8 @@ export const TorConnect = {
this._tryAgain = true; this._potentiallyBlocked = true; + // Disable quickstart until we have a successful bootstrap. + Services.prefs.setBoolPref(TorConnectPrefs.prompt_at_startup, true);
this._signalError(error);
===================================== toolkit/modules/TorSettings.sys.mjs ===================================== @@ -711,10 +711,15 @@ class TorSettingsImpl { * * Even though this introduces a circular depdency, it makes the API nicer for * frontend consumers. + * + * @param {boolean} flush - Whether to also flush the settings to disk. */ - async #applySettings() { + async #applySettings(flush) { const provider = await lazy.TorProviderBuilder.build(); await provider.writeSettings(); + if (flush) { + provider.flushSettings(); + } }
/** @@ -974,7 +979,7 @@ class TorSettingsImpl { ]; const shouldApply = changes.some(prop => !unreadProps.includes(prop)); if (shouldApply) { - await this.#applySettings(); + await this.#applySettings(true); } }
@@ -1042,7 +1047,8 @@ class TorSettingsImpl {
// After checks are complete, we commit them. this.#temporaryBridgeSettings = bridgeSettings; - await this.#applySettings(); + // Do not flush the temporary bridge settings until they are saved. + await this.#applySettings(false); }
/**
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/909f72f...