tor-browser

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

commit 7d1b5f8680b8b27a14601acc8db03236af7da97a
parent 565bdd724162f2c8bd94ba66e24a302b7d1c6ff4
Author: Mark Striemer <mstriemer@mozilla.com>
Date:   Fri,  9 Jan 2026 06:31:26 +0000

Bug 1990552 - Use setting-control's extension controlled message for Network settings r=bvandersloot,mconley

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

Diffstat:
Mbrowser/components/preferences/main.inc.xhtml | 2+-
Mbrowser/components/preferences/main.js | 38++++++--------------------------------
Mbrowser/components/preferences/tests/browser_extension_controlled.js | 65+++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mbrowser/components/preferences/tests/head.js | 27++++++++++++++++++++++++---
Mbrowser/components/preferences/widgets/setting-control/setting-control.css | 2+-
Mbrowser/components/preferences/widgets/setting-control/setting-control.mjs | 9++++++++-
Mtoolkit/content/preferences/Setting.mjs | 4+++-
7 files changed, 92 insertions(+), 55 deletions(-)

diff --git a/browser/components/preferences/main.inc.xhtml b/browser/components/preferences/main.inc.xhtml @@ -528,7 +528,7 @@ <label class="search-header" hidden="true"><html:h2 data-l10n-id="network-settings-title"/></label> <description flex="1" control="connectionSettings" data-subcategory="netsettings" class="section-description"> - <html:span id="connectionSettingsDescription"/> + <html:span id="connectionSettingsDescription" data-l10n-id="network-proxy-connection-description"/> <html:a is="moz-support-link" data-l10n-id="network-proxy-connection-learn-more" support-page="prefs-connection-settings" diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -774,6 +774,11 @@ Preferences.addSetting({ Preferences.addSetting({ id: "connectionSettings", onUserClick: () => gMainPane.showConnections(), + controllingExtensionInfo: { + storeId: PROXY_KEY, + l10nId: "extension-controlling-proxy-config", + allowControl: true, + }, }); Preferences.addSetting({ @@ -3044,10 +3049,6 @@ SettingGroupManager.registerGroups({ "search-l10n-ids": "connection-window2.title,connection-proxy-option-no.label,connection-proxy-option-auto.label,connection-proxy-option-system.label,connection-proxy-option-wpad.label,connection-proxy-option-manual.label,connection-proxy-http,connection-proxy-https,connection-proxy-http-port,connection-proxy-socks,connection-proxy-socks4,connection-proxy-socks5,connection-proxy-noproxy,connection-proxy-noproxy-desc,connection-proxy-https-sharing.label,connection-proxy-autotype.label,connection-proxy-reload.label,connection-proxy-autologin-checkbox.label,connection-proxy-socks-remote-dns.label", }, - // Bug 1990552: due to how this lays out in the legacy page, we do not include a - // controllingExtensionInfo attribute here. We will want one in the redesigned page, - // using storeId: "proxy.settings". - controllingExtensionInfo: undefined, }, ], }, @@ -4563,8 +4564,6 @@ var gMainPane = { } this.displayUseSystemLocale(); - this.updateProxySettingsUI(); - initializeProxyUI(gMainPane); if (Services.prefs.getBoolPref("intl.multilingual.enabled")) { gMainPane.initPrimaryBrowserLanguageUI(); @@ -5745,33 +5744,8 @@ var gMainPane = { */ showConnections() { gSubDialog.open( - "chrome://browser/content/preferences/dialogs/connection.xhtml", - { closingCallback: this.updateProxySettingsUI.bind(this) } - ); - }, - - // Update the UI to show the proper description depending on whether an - // extension is in control or not. - async updateProxySettingsUI() { - let controllingExtension = await getControllingExtension( - PREF_SETTING_TYPE, - PROXY_KEY + "chrome://browser/content/preferences/dialogs/connection.xhtml" ); - let description = document.getElementById("connectionSettingsDescription"); - - if (controllingExtension) { - setControllingExtensionDescription( - description, - controllingExtension, - "proxy.settings" - ); - } else { - setControllingExtensionDescription( - description, - null, - "network-proxy-connection-description" - ); - } }, // FONTS diff --git a/browser/components/preferences/tests/browser_extension_controlled.js b/browser/components/preferences/tests/browser_extension_controlled.js @@ -861,6 +861,21 @@ add_task(async function testExtensionControlledWebNotificationsPermission() { "The extension controlled row is now hidden" ); + // Close the site permissions dialog and wait for it to finish closing + let dialogClosed = BrowserTestUtils.waitForEvent( + gBrowser.contentWindow.gSubDialog._dialogStack, + "dialogclose" + ); + sitePermissionsDialog.document + .querySelector("dialog") + .getButton("cancel") + .click(); + await dialogClosed; + sitePermissionsDialog = null; + + // Wait a tick to allow cleanup to complete + await new Promise(resolve => Services.tm.dispatchToMainThread(resolve)); + await extension.unload(); BrowserTestUtils.removeTab(gBrowser.selectedTab); }); @@ -1167,7 +1182,7 @@ add_task(async function testExtensionControlledProxyConfig() { const EXTENSION_ID = "@set_proxy"; const CONTROLLED_SECTION_ID = "proxyExtensionContent"; const CONTROLLED_BUTTON_ID = "disableProxyExtension"; - const CONNECTION_SETTINGS_DESC_ID = "connectionSettingsDescription"; + const CONNECTION_SETTINGS_SETTING_ID = "connectionSettings"; const PANEL_URL = "chrome://browser/content/preferences/dialogs/connection.xhtml"; @@ -1177,18 +1192,41 @@ add_task(async function testExtensionControlledProxyConfig() { browser.proxy.settings.set({ value: { proxyType: "none" } }); } - function expectedConnectionSettingsMessage(doc, isControlled) { - return isControlled - ? "extension-controlling-proxy-config" - : "network-proxy-connection-description"; + function assertConnectionSettingsMessage(doc, isControlled) { + let settingControl = getSettingControl( + CONNECTION_SETTINGS_SETTING_ID, + doc.ownerGlobal + ); + Assert.ok( + settingControl, + `Got setting for ${CONNECTION_SETTINGS_SETTING_ID}` + ); + let messageBar = settingControl.controlledMessageBarRef.value; + if (isControlled) { + Assert.ok(messageBar, "Controlled message exists"); + Assert.ok( + BrowserTestUtils.isVisible(messageBar), + "Controlled message exists" + ); + } else { + Assert.ok(!messageBar, "Controlled message does not exist"); + } } - function connectionSettingsMessagePromise(doc, isControlled) { - return waitForMessageContent( - CONNECTION_SETTINGS_DESC_ID, - expectedConnectionSettingsMessage(doc, isControlled), - doc + async function connectionSettingsMessagePromise(doc, isControlled) { + let settingControl = getSettingControl( + CONNECTION_SETTINGS_SETTING_ID, + doc.ownerGlobal + ); + Assert.ok( + settingControl, + `Got setting for ${CONNECTION_SETTINGS_SETTING_ID}` ); + let messageBar = settingControl.controlledMessageBarRef.value; + if (isControlled != messageBar) { + await waitForSettingChange(settingControl.setting); + } + assertConnectionSettingsMessage(doc, isControlled); } function verifyProxyState(doc, isControlled) { @@ -1275,12 +1313,7 @@ add_task(async function testExtensionControlledProxyConfig() { ); } } else { - let elem = doc.getElementById(CONNECTION_SETTINGS_DESC_ID); - is( - doc.l10n.getAttributes(elem).id, - expectedConnectionSettingsMessage(doc, isControlled), - "The connection settings description is as expected." - ); + assertConnectionSettingsMessage(doc, isControlled); } } diff --git a/browser/components/preferences/tests/head.js b/browser/components/preferences/tests/head.js @@ -1,6 +1,10 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +/** + * @import { SettingControl } from "chrome://browser/content/preferences/widgets/setting-control.mjs" + */ + const { NimbusTestUtils } = ChromeUtils.importESModule( "resource://testing-common/NimbusTestUtils.sys.mjs" ); @@ -773,16 +777,33 @@ async function waitForSettingControlChange(control) { * Wait for the current setting pane to change. * * @param {string} paneId + * @param {Window} [win] The window to check, defaults to current window. */ -async function waitForPaneChange(paneId) { - let doc = gBrowser.selectedBrowser.contentDocument; - let event = await BrowserTestUtils.waitForEvent(doc, "paneshown"); +async function waitForPaneChange( + paneId, + win = gBrowser.selectedBrowser.ownerGlobal +) { + let event = await BrowserTestUtils.waitForEvent(win.document, "paneshown"); let expectId = paneId.startsWith("pane") ? paneId : `pane${paneId[0].toUpperCase()}${paneId.substring(1)}`; is(event.detail.category, expectId, "Loaded the correct pane"); } +/** + * Get a reference to the setting-control for a specific setting ID. + * + * @param {string} settingId The setting ID + * @param {Window} [win] The window to check, defaults to current window. + * @returns {SettingControl} + */ +function getSettingControl( + settingId, + win = gBrowser.selectedBrowser.ownerGlobal +) { + return win.document.getElementById(`setting-control-${settingId}`); +} + function getControl(doc, id) { let control = doc.getElementById(id); ok(control, `Control ${id} exists`); diff --git a/browser/components/preferences/widgets/setting-control/setting-control.css b/browser/components/preferences/widgets/setting-control/setting-control.css @@ -4,7 +4,7 @@ .extension-controlled-message-bar, .reenable-extensions-message-bar { - margin-block: var(--space-large); + margin-block-end: var(--space-large); } setting-control[hidden]:has(> moz-message-bar):not([slot="nested"]) { diff --git a/browser/components/preferences/widgets/setting-control/setting-control.mjs b/browser/components/preferences/widgets/setting-control/setting-control.mjs @@ -263,7 +263,7 @@ export class SettingControl extends SettingElement { "?disabled": this.setting.disabled || this.setting.locked || - this.isControlledByExtension(), + this.isDisabledByExtension(), // Hide moz-message-bar directly to maintain the role=alert functionality. // This setting-control will be visually hidden in CSS. ".hidden": config.control == "moz-message-bar" && this.hidden, @@ -329,6 +329,13 @@ export class SettingControl extends SettingElement { ); } + isDisabledByExtension() { + return ( + this.isControlledByExtension() && + !this.setting.controllingExtensionInfo.allowControl + ); + } + handleEnableExtensionDismiss() { this.showEnableExtensionMessage = false; } diff --git a/toolkit/content/preferences/Setting.mjs b/toolkit/content/preferences/Setting.mjs @@ -109,6 +109,8 @@ import { Preferences } from "chrome://global/content/preferences/Preferences.mjs * @property {string} l10nId A fluent id to show in a controlled by extension message. * @property {string} [name] The controlling extension's name. * @property {string} [id] The controlling extension's id. + * @property {string} [supportPage] A support page to show in the message. + * @property {boolean} [allowControl] If the control should be enabled while controlled. */ /** @@ -116,7 +118,7 @@ import { Preferences } from "chrome://global/content/preferences/Preferences.mjs * @property {string} id - The ID for the Setting, this should match the layout id * @property {string} [pref] - A {@link Services.prefs} id that will be used as the backend if it is provided * @property {string[]} [deps] - An array of setting IDs that this setting depends on, when these settings change this setting will emit a change event to update the UI - * @property {Pick<SettingControllingExtensionInfo, "storeId" | "l10nId">} [controllingExtensionInfo] Data related to the setting being controlled by an extension. + * @property {Pick<SettingControllingExtensionInfo, "storeId" | "l10nId" | "allowControl" | "supportPage">} [controllingExtensionInfo] Data related to the setting being controlled by an extension. * @property {SettingVisibleCallback} [visible] - Function to determine if a setting is visible in the UI * @property {SettingGetCallback} [get] - Function to get the value of the setting. Optional if {@link SettingConfig#pref} is set. * @property {SettingSetCallback} [set] - Function to set the value of the setting. Optional if {@link SettingConfig#pref} is set.