tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 62d880e6871af6b44989c657d13a23ae0b0402ca
parent 9f26e2a434251442c1210649c78e3096e3a6f875
Author: Henry Wilkes <henry@torproject.org>
Date:   Tue,  4 Mar 2025 15:15:36 +0000

TB 43405: Show a prompt whenever we fail to apply Tor settings.

Diffstat:
Mbrowser/components/BrowserComponents.manifest | 1+
Abrowser/modules/TorSettingsNotification.sys.mjs | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/modules/moz.build | 1+
3 files changed, 169 insertions(+), 0 deletions(-)

diff --git a/browser/components/BrowserComponents.manifest b/browser/components/BrowserComponents.manifest @@ -61,6 +61,7 @@ category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init category browser-first-window-ready moz-src:///browser/modules/SecurityLevelNotification.sys.mjs SecurityLevelNotification.ready category browser-first-window-ready moz-src:///toolkit/modules/DragDropFilter.sys.mjs DragDropFilter.init +category browser-first-window-ready moz-src:///browser/modules/TorSettingsNotification.sys.mjs TorSettingsNotification.ready category browser-idle-startup moz-src:///browser/components/places/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes diff --git a/browser/modules/TorSettingsNotification.sys.mjs b/browser/modules/TorSettingsNotification.sys.mjs @@ -0,0 +1,167 @@ +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs", + TorSettings: "resource://gre/modules/TorSettings.sys.mjs", + TorSettingsTopics: "resource://gre/modules/TorSettings.sys.mjs", +}); + +ChromeUtils.defineLazyGetter(lazy, "NotificationStrings", function () { + return new Localization(["toolkit/global/tor-browser.ftl"]); +}); + +/** + * Shows a notification whenever we get an ApplyError. + */ +export const TorSettingsNotification = { + /** + * Whether we have already been initialised. + * + * @type {boolean} + */ + _initialized: false, + + /** + * Called when the UI is ready to show a notification. + */ + ready() { + if (this._initialized) { + return; + } + this._initialized = true; + Services.obs.addObserver(this, lazy.TorSettingsTopics.ApplyError); + + // Show the notification for each group of settings if they have an error + // that was triggered prior to `ready` being called. + this.showNotification("bridges"); + this.showNotification("proxy"); + this.showNotification("firewall"); + }, + + observe(subject, topic) { + if (topic === lazy.TorSettingsTopics.ApplyError) { + this.showNotification(subject.wrappedJSObject.group); + } + }, + + /** + * A promise for the `showNotification` method to ensure we only show one + * notification at a time. + * + * @type {?Promise} + */ + _notificationPromise: null, + + /** + * Show a notification for the given group of settings if `TorSettings` has an + * error for them. + * + * @param {string} group - The settings group to show the notification for. + */ + async showNotification(group) { + const prevNotificationPromise = this._notificationPromise; + let notificationComplete; + ({ promise: this._notificationPromise, resolve: notificationComplete } = + Promise.withResolvers()); + // Only want to show one notification at a time, so queue behind the + // previous one. + await prevNotificationPromise; + + // NOTE: We only show the notification for a single `group` at a time, even + // when TorSettings has errors for multiple groups. This keeps the strings + // simple and means we can show different buttons depending on `canUndo` for + // each group individually. + // If we do have multiple errors the notification for each group will simply + // queue behind each other. + try { + // Grab the latest error value, which may have changed since + // showNotification was first called. + const error = lazy.TorSettings.getApplyError(group); + if (!error) { + // No current error for this group. + return; + } + + const { canUndo } = error; + + let titleId; + let introId; + switch (group) { + case "bridges": + titleId = "tor-settings-failed-notification-title-bridges"; + introId = "tor-settings-failed-notification-cause-bridges"; + break; + case "proxy": + titleId = "tor-settings-failed-notification-title-proxy"; + introId = "tor-settings-failed-notification-cause-proxy"; + break; + case "firewall": + titleId = "tor-settings-failed-notification-title-firewall"; + introId = "tor-settings-failed-notification-cause-firewall"; + break; + } + + const [ + titleText, + introText, + bodyText, + primaryButtonText, + secondaryButtonText, + ] = await lazy.NotificationStrings.formatValues([ + { id: titleId }, + { id: introId }, + { + id: canUndo + ? "tor-settings-failed-notification-body-undo" + : "tor-settings-failed-notification-body-default", + }, + { + id: canUndo + ? "tor-settings-failed-notification-button-undo" + : "tor-settings-failed-notification-button-clear", + }, + { id: "tor-settings-failed-notification-button-fix-myself" }, + ]); + + const propBag = await Services.prompt.asyncConfirmEx( + lazy.BrowserWindowTracker.getTopWindow()?.browsingContext ?? null, + Services.prompt.MODAL_TYPE_INTERNAL_WINDOW, + titleText, + // Concatenate the intro text and the body text. Really these should be + // separate paragraph elements, but the prompt service does not support + // this. We split them with a double newline, which will hopefully avoid + // the usual problems with concatenating localised strings. + `${introText}\n\n${bodyText}`, + Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 + + Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_1, + primaryButtonText, + secondaryButtonText, + null, + null, + null, + {} + ); + + const buttonNum = propBag.get("buttonNumClicked"); + + if (buttonNum === 0) { + if (canUndo) { + // Wait for these methods in case they resolve the error for a pending + // showNotification call. + await lazy.TorSettings.undoFailedSettings(group); + } else { + await lazy.TorSettings.clearFailedSettings(group); + } + } else if (buttonNum === 1) { + let win = lazy.BrowserWindowTracker.getTopWindow(); + if (!win) { + win = await lazy.BrowserWindowTracker.promiseOpenWindow(); + } + // Open the preferences or switch to its tab and highlight the Tor log. + win.openPreferences("connection-viewlogs"); + } + } finally { + notificationComplete(); + } + }, +}; diff --git a/browser/modules/moz.build b/browser/modules/moz.build @@ -155,6 +155,7 @@ MOZ_SRC_FILES += [ "ObserverForwarder.sys.mjs", "PrivateBrowsingUI.sys.mjs", "SecurityLevelNotification.sys.mjs", + "TorSettingsNotification.sys.mjs", "UnexpectedScriptObserver.sys.mjs", "WebAuthnPromptHelper.sys.mjs", ]