henry pushed to branch tor-browser-153.0esr-16.0-1 at The Tor Project / Applications / Tor Browser Commits: 87ad933f by Henry Wilkes at 2026-07-30T16:37:03+00:00 fixup! Tor Browser strings TB 45051: Add notification strings. - - - - - 1676ad67 by Henry Wilkes at 2026-07-30T16:37:03+00:00 TB 45051: Add an external tor provider notification. - - - - - 4 changed files: - browser/components/BrowserComponents.manifest - + browser/modules/TorProviderExternalNotification.sys.mjs - browser/modules/moz.build - toolkit/locales/en-US/toolkit/global/tor-browser.ftl Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -64,6 +64,7 @@ category browser-window-delayed-startup resource:///modules/HomePage.sys.mjs Hom category browser-window-delayed-startup moz-src:///browser/components/reportbrokensite/ReportBrokenSite.sys.mjs ReportBrokenSite.init category browser-window-delayed-startup moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchUIUtils.init category browser-window-delayed-startup resource:///modules/taskbartabs/TaskbarTabsPageAction.sys.mjs TaskbarTabsPageAction.init +category browser-window-delayed-startup moz-src:///browser/modules/TorProviderExternalNotification.sys.mjs TorProviderExternalNotification.delayedStartup category browser-window-location-change chrome://browser/content/browser-places.js BookmarkingUI.onLocationChange category browser-window-location-change chrome://browser/content/browser-sitePermissionPanel.js gPermissionPanel.onLocationChange @@ -93,6 +94,7 @@ category browser-window-unload chrome://browser/content/browser.js#CombinedStopR category browser-window-unload chrome://browser/content/browser-addons.js gUnifiedExtensions.uninit category browser-window-unload chrome://browser/content/browser.js#FirefoxViewHandler FirefoxViewHandler.uninit category browser-window-unload moz-src:///browser/components/tabbrowser/NewTabPagePreloading.sys.mjs NewTabPagePreloading.removePreloadedBrowser +category browser-window-unload moz-src:///browser/modules/TorProviderExternalNotification.sys.mjs TorProviderExternalNotification.unload # The category below is specific to Tabbrowser destruction. For consumers that need to uninitialize during # window unload, use 'browser-window-unload' instead. ===================================== browser/modules/TorProviderExternalNotification.sys.mjs ===================================== @@ -0,0 +1,219 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs", + TorConnect: "moz-src:///toolkit/modules/TorConnect.sys.mjs", + TorProviderBuilder: + "moz-src:///toolkit/components/tor-launcher/TorProviderBuilder.sys.mjs", + TorProviderState: + "moz-src:///toolkit/components/tor-launcher/TorProviderBuilder.sys.mjs", + TorProviderTopics: + "moz-src:///toolkit/components/tor-launcher/TorProviderBuilder.sys.mjs", +}); + +export const TorProviderExternalNotification = { + /** + * Whether we have been initialized. + * + * @type {boolean} + */ + _initialized: false, + + /** + * Callback for browser-window-delayed-startup. + * + * @param {Window} win - The browser window that was just loaded. + */ + delayedStartup(win) { + if (lazy.TorConnect.enabled) { + // Let TorConnect handle the ProviderStateChanged. + return; + } + + if (!this._initialized) { + this._initialized = true; + this._setProviderState(lazy.TorProviderBuilder.currentState()); + Services.obs.addObserver( + this, + lazy.TorProviderTopics.ProviderStateChanged + ); + } else { + // Maybe show the notification in the new window. + this._updateNotification(win); + } + }, + + /** + * Callback for browser-window-unload. + * + * @param {Window} win - The browser window that is being unloaded. + */ + unload(win) { + if (this._notification?.window === win) { + this._notification = null; + } + }, + + observe(subject, topic, data) { + switch (topic) { + case lazy.TorProviderTopics.ProviderStateChanged: + this._setProviderState(data); + break; + } + }, + + /** + * The last seen `TorProviderState` state. + * + * @type {?string} + */ + _providerState: null, + + /** + * Set the provider state. + * + * @param {string} state - The `TorProviderState` state we are now in. + */ + _setProviderState(state) { + if (this._providerState === state) { + // No change, ignore. + return; + } + + this._providerState = state; + // A new instance of a provider, so ignore any previously dismissed + // notifications. + this._notificationUserDismissed = false; + this._updateNotification(); + }, + + /** + * The notification that is currently shown. + * + * @type {?{ window: Window, elementPromise: Promise<NotificationMessage> }} + */ + _notification: null, + /** + * Whether the user has dismissed the notification for the current TorProvider + * instance. + * + * @type {boolean} + */ + _notificationUserDismissed: false, + + /** + * Update the notification depending on the latest `TorProviderState`. + * + * @param {Window} [win] - A newly opened browser window to maybe show the + * notification in. If not given, the notification might be shown in the + * current top window. + */ + _updateNotification(win) { + if (this._providerState === lazy.TorProviderState.Starting) { + this._updateNotificationButton( + "tor-external-process-error-retry-button-retrying" + ); + return; + } + + if (this._providerState === lazy.TorProviderState.Running) { + if (this._notification) { + // If there is a notification, close it. + const { elementPromise } = this._notification; + this._notification = null; + elementPromise.then(el => el.remove()); + } + return; + } + // Else, _providerState is TorProviderState.Stopped. + + if (this._notificationUserDismissed) { + // User has already dismissed this in a different window. + return; + } + + if (this._notification) { + // Already showing. + this._updateNotificationButton("tor-external-process-error-retry-button"); + return; + } + + if (!win) { + win = lazy.BrowserWindowTracker.getTopWindow(); + if (!win) { + // Wait for a window. + return; + } + } + + const buttons = [ + { + supportPage: "tor-manual:get-in-touch__bug-or-feedback", + }, + { + "l10n-id": "tor-external-process-error-retry-button", + callback: () => { + if (this._providerState === lazy.TorProviderState.Stopped) { + lazy.TorProviderBuilder.replace(); + } + // Keep open. + return true; + }, + }, + ]; + + const notification = { + window: win, + elementPromise: win.gNotificationBox.appendNotification( + "tor-provider-external-process-stopped", + { + label: { "l10n-id": "tor-external-process-error-message" }, + priority: win.gNotificationBox.PRIORITY_WARNING_HIGH, + eventCallback: event => { + switch (event) { + case "dismissed": + this._notificationUserDismissed = true; + break; + case "disconnected": + if (this._notification === notification) { + this._notification = null; + } + break; + } + }, + }, + buttons + ), + }; + this._notification = notification; + }, + + /** + * Update the notification button if it exists. + * + * @param {string} l10nId - The Fluent ID for the string we want to show in + * the button. + */ + async _updateNotificationButton(l10nId) { + if (!this._notification) { + return; + } + const state = this._providerState; + const notification = this._notification; + const notificationEl = await notification.elementPromise; + + if (this._providerState !== state || this._notification !== notification) { + // Replaced. + return; + } + + notificationEl.buttonContainer.firstElementChild.setAttribute( + "data-l10n-id", + l10nId + ); + }, +}; ===================================== browser/modules/moz.build ===================================== @@ -154,6 +154,7 @@ MOZ_SRC_FILES += [ "ObserverForwarder.sys.mjs", "PrivateBrowsingUI.sys.mjs", "SecurityLevelNotification.sys.mjs", + "TorProviderExternalNotification.sys.mjs", "TorSettingsNotification.sys.mjs", "TorUIUtils.sys.mjs", ] ===================================== toolkit/locales/en-US/toolkit/global/tor-browser.ftl ===================================== @@ -46,6 +46,15 @@ tor-connect-tor-not-working-restarting-button = .label = Restarting Tor process… tor-connect-tor-not-working-restarting-failed = Restarting failed +## External Tor process error. + +# "{ -brand-short-name }" will be replaced with the localized name of the browser, e.g. "Tor Browser". +tor-external-process-error-message = { -brand-short-name } can’t communicate with your external Tor application, which may cause some browser features to malfunction. Check that the external application is running, or reconfigure its communication with { -brand-short-name }. +tor-external-process-error-retry-button = + .label = Retry communication +tor-external-process-error-retry-button-retrying = + .label = Retrying communication… + ## Tor Browser home page. tor-browser-home-heading-stable = Explore. Privately. View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/ae29506... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/ae29506... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help