tor-browser

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

commit 936fdf8ebfa062e69864b34fee89521500eaa031
parent c2ef83ec4b8ba8a680b84b598df8097e94e2226a
Author: Andrea Marchesini <amarchesini@mozilla.com>
Date:   Wed,  1 Oct 2025 14:08:58 +0000

Bug 1991700 - Fix the ipp add-on navigation logic, r=jaws

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

Diffstat:
Mbrowser/extensions/ipp-activator/extension/api/parent/ext-ipp.js | 43+++++++++++++++++++++++++++++--------------
Mbrowser/extensions/ipp-activator/extension/bg.js | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 87 insertions(+), 32 deletions(-)

diff --git a/browser/extensions/ipp-activator/extension/api/parent/ext-ipp.js b/browser/extensions/ipp-activator/extension/api/parent/ext-ipp.js @@ -180,7 +180,7 @@ this.ippActivator = class extends ExtensionAPI { const browser = tab?.linkedBrowser; const win = browser?.ownerGlobal; if (!browser || !win || !win.gBrowser) { - return; + return Promise.resolve(false); } const nbox = win.gBrowser.getNotificationBox(browser); @@ -215,22 +215,37 @@ this.ippActivator = class extends ExtensionAPI { const label = buildLabel(message); - const notification = await nbox.appendNotification( - id, - { - // If label is a string, pass it through; if it's a Node, the - // notification box will handle it as rich content. - label, - priority: nbox.PRIORITY_WARNING_HIGH, - }, - [] - ); + // Promise that resolves when the notification is dismissed + let resolveDismiss; + const dismissedPromise = new Promise(resolve => { + resolveDismiss = resolve; + }); + + // Create the notification; set persistence when available + nbox + .appendNotification( + id, + { + // If label is a string, pass it through; if it's a Node, the + // notification box will handle it as rich content. + label, + priority: nbox.PRIORITY_WARNING_HIGH, + eventCallback: param => { + resolveDismiss(param === "dismissed"); + }, + }, + [] + ) + .then(notification => { + // Persist the notification until the user removes so it + // doesn't get removed on redirects. + notification.persistence = -1; + }); - // Persist the notification until the user removes so it - // doesn't get removed on redirects. - notification.persistence = -1; + return dismissedPromise; } catch (e) { console.warn("Unable to show the message", e); + return Promise.resolve(false); } }, onDynamicTabBreakagesUpdated: new ExtensionCommon.EventManager({ diff --git a/browser/extensions/ipp-activator/extension/bg.js b/browser/extensions/ipp-activator/extension/bg.js @@ -74,6 +74,14 @@ class IPPAddonActivator { this.#unregisterListeners(); + // When IPP is deactivated, mark currently shown banners as consumed + const uniqueDomains = new Set(this.#shownDomainByTab.values()); + await Promise.allSettled( + Array.from(uniqueDomains).map(d => + browser.ippActivator.addNotifiedDomain(d) + ) + ); + const ids = Array.from(this.#shownDomainByTab.keys()); await Promise.allSettled( ids.map(id => browser.ippActivator.hideMessage(id)) @@ -206,7 +214,11 @@ class IPPAddonActivator { changeInfo.url || tab?.url || "" ); const shownBase = this.#shownDomainByTab.get(tabId); - if (shownBase && shownBase !== info.baseDomain) { + if ( + shownBase && + shownBase !== info.baseDomain && + shownBase !== info.host + ) { await browser.ippActivator.hideMessage(tabId); this.#shownDomainByTab.delete(tabId); } @@ -278,22 +290,24 @@ class IPPAddonActivator { return false; } - // Do not show the same notification again for the same base domain. - const shown = await browser.ippActivator.getNotifiedDomains(); - if ( - info.baseDomain && - Array.isArray(shown) && - shown.includes(info.baseDomain) - ) { - return false; - } - - const breakage = breakages.find( - b => - Array.isArray(b.domains) && - (b.domains.includes(info.baseDomain) || b.domains.includes(info.host)) + let domain = info.baseDomain; + let breakage = breakages.find( + b => Array.isArray(b.domains) && b.domains.includes(info.baseDomain) ); if (!breakage) { + breakage = breakages.find( + b => Array.isArray(b.domains) && b.domains.includes(info.host) + ); + if (!breakage) { + return false; + } + + domain = info.host; + } + + // Do not show the same notification again for the same base domain. + const shown = await browser.ippActivator.getNotifiedDomains(); + if (Array.isArray(shown) && shown.includes(domain)) { return false; } @@ -303,11 +317,37 @@ class IPPAddonActivator { return false; } - await browser.ippActivator.showMessage(breakage.message, tab.id); // Track which base domain this tab is showing a notification for - this.#shownDomainByTab.set(tab.id, info.baseDomain); + this.#shownDomainByTab.set(tab.id, domain); + + // This function returns when the notification is dismissed. We don't want + // to wait for that to happen. + browser.ippActivator + .showMessage(breakage.message, tab.id) + .then(async dismissed => { + if (!dismissed) { + return; + } + + await browser.ippActivator.addNotifiedDomain(domain); - await browser.ippActivator.addNotifiedDomain(info.baseDomain); + // Close all notifications currently shown for the same base domain + // across all tabs and clean up tracking state. + const toClose = []; + for (const [tid, base] of this.#shownDomainByTab.entries()) { + if (base === domain) { + toClose.push(tid); + } + } + + await Promise.allSettled( + toClose.map(id => browser.ippActivator.hideMessage(id)) + ); + + for (const id of toClose) { + this.#shownDomainByTab.delete(id); + } + }); return true; }