tor-browser

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

commit ecb3b20217d69d2ce8fbf64f68b1c8d7b52a2343
parent d3ed13dc566ee2fb9c39d9235d7847cb215d58c8
Author: Thomas Wisniewski <twisniewski@mozilla.com>
Date:   Fri, 24 Oct 2025 15:29:46 +0000

Bug 1996081 - Add the ability to enable/disable individual webcompat interventions with about:config prefs; r=denschub,webcompat-reviewers

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

Diffstat:
Mbrowser/extensions/webcompat/lib/interventions.js | 60+++++++++++++++++++++++++++++++++++++++++++++++-------------
Mbrowser/extensions/webcompat/tests/browser/browser.toml | 1+
Mbrowser/extensions/webcompat/tests/browser/browser_intervention_gating.js | 275+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 323 insertions(+), 13 deletions(-)

diff --git a/browser/extensions/webcompat/lib/interventions.js b/browser/extensions/webcompat/lib/interventions.js @@ -16,6 +16,8 @@ class Interventions { this._readyPromise = new Promise(done => (this._resolveReady = done)); + this._disabledPrefListeners = {}; + this._availableInterventions = this._reformatSourceJSON( availableInterventions ); @@ -96,19 +98,6 @@ class Interventions { }); } - checkOverridePref() { - navigator.locks.request("pref_check_lock", async () => { - const value = await browser.aboutConfigPrefs.getPref(this.OVERRIDE_PREF); - if (value === undefined) { - await browser.aboutConfigPrefs.setPref(this.OVERRIDE_PREF, true); - } else if (value === false) { - await this.unregisterUAOverrides(); - } else { - await this.registerUAOverrides(); - } - }); - } - getAvailableInterventions() { return this._availableInterventions; } @@ -132,6 +121,14 @@ class Interventions { ) { return navigator.locks.request("intervention_lock", async () => { for (const config of whichInterventions) { + const disabling_pref_listener = this._disabledPrefListeners[config.id]; + if (disabling_pref_listener) { + browser.aboutConfigPrefs.onPrefChange.removeListener( + disabling_pref_listener + ); + delete this._disabledPrefListeners[config.id]; + } + await this._disableInterventionNow(config); } @@ -205,6 +202,39 @@ class Interventions { continue; } + config.DISABLING_PREF = `disabled_interventions.${config.id}`; + const disabledPrefListener = () => { + navigator.locks.request("pref_check_lock", async () => { + const value = await browser.aboutConfigPrefs.getPref( + config.DISABLING_PREF + ); + if (value === true) { + await this.disableIntervention(config); + console.debug( + `Webcompat intervention for ${config.label} disabled by pref` + ); + } else { + await this.enableIntervention(config); + console.debug( + `Webcompat intervention for ${config.label} enabled by pref` + ); + } + this._aboutCompatBroker.portsToAboutCompatTabs.broadcast({ + interventionsChanged: + this._aboutCompatBroker.filterInterventions(whichInterventions), + }); + }); + }; + this._disabledPrefListeners[config.id] = disabledPrefListener; + browser.aboutConfigPrefs.onPrefChange.addListener( + disabledPrefListener, + config.DISABLING_PREF + ); + + const disablingPrefValue = await browser.aboutConfigPrefs.getPref( + config.DISABLING_PREF + ); + for (const intervention of config.interventions) { intervention.enabled = false; if (!(await this._check_for_needed_prefs(intervention))) { @@ -246,6 +276,10 @@ class Interventions { skipped.push(config.label); continue; } + if (disablingPrefValue === true) { + skipped.push(config.label); + continue; + } try { await this._enableInterventionNow(config); diff --git a/browser/extensions/webcompat/tests/browser/browser.toml b/browser/extensions/webcompat/tests/browser/browser.toml @@ -11,6 +11,7 @@ support-files = [ "smartblock_embed_test.html", "embed_test.js", ] +prefs = ["extensions.webcompat.disabled_interventions.test6=true","extensions.webcompat.disabled_interventions.test7=false"] ["browser_aboutcompat.js"] skip-if = ["debug"] # disabled until bug 1961939 is fixed. diff --git a/browser/extensions/webcompat/tests/browser/browser_intervention_gating.js b/browser/extensions/webcompat/tests/browser/browser_intervention_gating.js @@ -250,3 +250,278 @@ add_task(async function test_disabling_by_default() { await WebCompatExtension.disableInterventions(["test3", "test4"]); }); + +add_task(async function test_individual_interventions_prefs() { + const config5 = getConfig("test5", [ + { + js: ["lib/run.js"], + }, + ]); + // the pref for this one is set to true before app-startup + const config6 = getConfig("test6", [ + { + js: ["lib/shims.js"], + }, + ]); + // the pref for this one is set to false before app-startup + const config7 = getConfig("test7", [ + { + js: ["lib/custom_functions.js"], + }, + ]); + let configs = await WebCompatExtension.updateInterventions([ + config5, + config6, + config7, + ]); + Assert.deepEqual( + configs.map(c => c.active), + [true, false, true], + "The correct interventions were activated on startup" + ); + Assert.deepEqual( + configs.map(c => c.interventions.map(i => i.enabled)), + [[true], [true], [true]], + "The correct interventions were made available on startup" + ); + let reg = await WebCompatExtension.getRegisteredContentScriptsFor(["test"]); + Assert.deepEqual( + reg.map(r => r.js).flat(), + ["lib/run.js", "lib/custom_functions.js"], + "The correct content scripts were registered on startup" + ); + + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test5", + true + ); + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test6", + false + ); + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test7", + true + ); + await WebCompatExtension.noOngoingInterventionChanges(); + configs = await WebCompatExtension.updateInterventions([ + config5, + config6, + config7, + ]); + Assert.deepEqual( + configs.map(c => c.active), + [false, true, false], + "The correct interventions were activated by pref changes" + ); + Assert.deepEqual( + configs.map(c => c.interventions.map(i => i.enabled)), + [[true], [true], [true]], + "The correct interventions were made available by pref changes" + ); + reg = await WebCompatExtension.getRegisteredContentScriptsFor(["test"]); + Assert.deepEqual( + reg.map(r => r.js).flat(), + ["lib/shims.js"], + "The correct content scripts are registered after pref changes" + ); + + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test5", + false + ); + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test6", + true + ); + Services.prefs.setBoolPref( + "extensions.webcompat.disabled_interventions.test7", + false + ); + await WebCompatExtension.noOngoingInterventionChanges(); + configs = await WebCompatExtension.updateInterventions([ + config5, + config6, + config7, + ]); + Assert.deepEqual( + configs.map(c => c.active), + [true, false, true], + "The correct interventions were activated by pref changes" + ); + Assert.deepEqual( + configs.map(c => c.interventions.map(i => i.enabled)), + [[true], [true], [true]], + "The correct interventions were made available by pref changes" + ); + reg = await WebCompatExtension.getRegisteredContentScriptsFor(["test"]); + Assert.deepEqual( + reg.map(r => r.js).flat(), + ["lib/run.js", "lib/custom_functions.js"], + "The correct content scripts are registered after pref changes" + ); + + const tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: "about:compat", + waitForLoad: true, + }); + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + is( + content.origin, + "moz-extension://9a310967-e580-48bf-b3e8-4eafebbc122d", + "Expected origin of about:compat" + ); + + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-disable]" + ), + "test5 is correctly shown as disabled" + ); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test6] [data-l10n-id=label-enable]" + ), + "test6 is correctly shown as enabled" + ); + + // click to disable test5 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-disable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-enable]" + ), + "test5 is correctly disabled" + ); + + // click to enable test6 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test6] [data-l10n-id=label-enable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test6] [data-l10n-id=label-disable]" + ), + "test6 is correctly enabled" + ); + + // click to disable test7 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test7] [data-l10n-id=label-disable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-enable]" + ), + "test7 is correctly disabled" + ); + }); + + configs = [ + await WebCompatExtension.getInterventionById("test5"), + await WebCompatExtension.getInterventionById("test6"), + await WebCompatExtension.getInterventionById("test7"), + ]; + Assert.deepEqual( + configs.map(c => c.active), + [false, true, false], + "The correct interventions were activated by about:compat changes" + ); + Assert.deepEqual( + configs.map(c => c.interventions.map(i => i.enabled)), + [[true], [true], [true]], + "The correct interventions were made available by about:compat changes" + ); + reg = await WebCompatExtension.getRegisteredContentScriptsFor(["test"]); + Assert.deepEqual( + reg.map(r => r.js).flat(), + ["lib/shims.js"], + "The correct content scripts are registered after about:compat changes" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async function () { + // click to re-enable test5 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-enable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test5] [data-l10n-id=label-disable]" + ), + "test5 is correctly disabled" + ); + + // click to re-disable test6 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test6] [data-l10n-id=label-disable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test6] [data-l10n-id=label-enable]" + ), + "test6 is correctly disabled" + ); + + // click to re-enable test7 and confirm + content.document + .querySelector( + "#interventions tr[data-id=test7] [data-l10n-id=label-enable]" + ) + .click(); + await ContentTaskUtils.waitForCondition( + () => + content.document.querySelector( + "#interventions tr[data-id=test7] [data-l10n-id=label-disable]" + ), + "test7 is correctly disabled" + ); + }); + await BrowserTestUtils.removeTab(tab); + + configs = [ + await WebCompatExtension.getInterventionById("test5"), + await WebCompatExtension.getInterventionById("test6"), + await WebCompatExtension.getInterventionById("test7"), + ]; + Assert.deepEqual( + configs.map(c => c.active), + [true, false, true], + "The correct interventions were activated by about:compat changes" + ); + Assert.deepEqual( + configs.map(c => c.interventions.map(i => i.enabled)), + [[true], [true], [true]], + "The correct interventions were made available by about:compat changes" + ); + reg = await WebCompatExtension.getRegisteredContentScriptsFor(["test"]); + Assert.deepEqual( + reg.map(r => r.js).flat(), + ["lib/run.js", "lib/custom_functions.js"], + "The correct content scripts are registered after about:compat changes" + ); + + await WebCompatExtension.disableInterventions(["test5", "test6", "test7"]); + Services.prefs.clearUserPref( + "extensions.webcompat.disabled_interventions.test5" + ); +});