tor-browser

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

commit 8f39ccbc3c48ef0f2cadd9ec3320631c018cafb2
parent 898a38978a9b4f20082a5b1701aad864b92129b5
Author: Rob Wu <rob@robwu.nl>
Date:   Mon, 20 Oct 2025 14:12:25 +0000

Bug 1992983 - Add notice to extensions panel if in safe mode r=rpl,fluent-reviewers,bolsson

Differential Revision: https://phabricator.services.mozilla.com/D268460

Diffstat:
Mbrowser/base/content/browser-addons.js | 8++++++++
Mbrowser/components/extensions/test/browser/browser_unified_extensions_empty_panel.js | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/locales/en-US/browser/unifiedExtensions.ftl | 3+++
3 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js @@ -2485,6 +2485,14 @@ var gUnifiedExtensions = { "#unified-extensions-messages-container" ); + if (Services.appinfo.inSafeMode) { + this._messageBarSafemode ??= this._makeMessageBar({ + messageBarFluentId: "unified-extensions-notice-safe-mode", + type: "info", + }); + container.prepend(this._messageBarSafemode); + } // No "else" case; inSafeMode flag is fixed at browser startup. + if (this.blocklistAttentionInfo?.shouldShow) { this._messageBarBlocklist = this._createBlocklistMessageBar(container); } else { diff --git a/browser/components/extensions/test/browser/browser_unified_extensions_empty_panel.js b/browser/components/extensions/test/browser/browser_unified_extensions_empty_panel.js @@ -629,3 +629,51 @@ add_task(async function test_empty_state_with_blocklisted_addon_hardblock() { add_task(async function test_empty_state_with_blocklisted_addon_softblock() { await do_test_empty_state_with_blocklisted_addon(/* isSoftBlock */ true); }); + +add_task(async function test_safe_mode_notice() { + const sandbox = sinon.createSandbox(); + registerCleanupFunction(() => sandbox.restore()); + + // Services.appinfo.inSafeMode is ordinarily a constant fixed at browser + // startup. We fake its implementation, and use a separate browser window in + // the test to make sure that any state derived from reading the inSafeMode + // flag is limited to this window. + const win = await BrowserTestUtils.openNewBrowserWindow({ private: true }); + // Services.appinfo.inSafeMode is a non-configurable property, so to spoof + // its value we stub Services.appinfo and let it fall back to the original + // implementation for every property, except for inSafeMode. + const appinfoStub = new Proxy(Services.appinfo, { + get(target, propertyKey) { + if (propertyKey === "inSafeMode") { + return true; + } + return Reflect.get(target, propertyKey, target); + }, + }); + sandbox.stub(Services, "appinfo").get(() => appinfoStub); + await openExtensionsPanel(win); + + const messages = getMessageBars(win); + is(messages.length, 1, "Got one message bar"); + const bar = messages[0]; + is(bar.getAttribute("type"), "info", "Bar is informational notice"); + ok(!bar.hasAttribute("dismissable"), "Bar is not dismissable"); + + // We don't exactly care which empty state is shown, as the notice is + // independent of the empty state. We just verify as a sanity check that the + // panel is indeed empty, which is most realistic when users enter safe mode. + let emptyStateBox = getEmptyStateContainer(win); + ok(BrowserTestUtils.isVisible(emptyStateBox), "Empty state is visible"); + + await closeExtensionsPanel(win); + + // Closing and re-opening should show one bar. + await openExtensionsPanel(win); + is(getMessageBars(win).length, 1, "Still one bar"); + await closeExtensionsPanel(win); + + sandbox.restore(); + is(Services.appinfo.inSafeMode, false, "Restored original inSafeMode"); + + await BrowserTestUtils.closeWindow(win); +}); diff --git a/browser/locales/en-US/browser/unifiedExtensions.ftl b/browser/locales/en-US/browser/unifiedExtensions.ftl @@ -56,6 +56,9 @@ unified-extensions-context-menu-move-widget-down = ## Notifications +unified-extensions-notice-safe-mode = + .message = All extensions have been disabled by Troubleshoot Mode. + # .heading is processed by moz-message-bar to be used as a heading attribute unified-extensions-mb-quarantined-domain-message-3 = .heading = Some extensions are not allowed