tor-browser

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

commit ace97753a39d1c1c5c60e06930e4b9f8bbc1305e
parent 6456a9a5ef16260ea4d336cfcf2ac0a47adc6ce5
Author: smayya <smayya@mozilla.com>
Date:   Sat, 13 Dec 2025 22:46:37 +0000

Bug 2002810 - Add 5-minute timeout for Local Network Access permission prompts. r=emz

Add automatic timeout handling to LNA (Local Network Access) permission prompts
to prevent prompts from remaining on screen indefinitely. If the user doesn't
respond within 5 minutes, the prompt is automatically dismissed and the network
request fails.

Implementation:
- Created LNAPermissionPromptBase class extending PermissionPromptForRequest
- Added timeout logic using lazy.setTimeout from Timer module
- LocalHostPermissionPrompt and LocalNetworkPermissionPrompt now extend the base class
- When timeout expires: dismisses UI popup via PopupNotifications.remove() and cancels request
- Timer is cleared when user responds (Allow/Cancel) or prompt is dismissed

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

Diffstat:
Mbrowser/app/profile/firefox.js | 3+++
Mbrowser/modules/PermissionUI.sys.mjs | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -1337,6 +1337,9 @@ pref("network.captive-portal-service.enabled", true); // If true, network link events will change the value of navigator.onLine pref("network.manage-offline-status", true); +// timeout for local network access prompts +pref("network.lna.prompt.timeout", 300000); // 5 minutes + // We want to make sure mail URLs are handled externally... pref("network.protocol-handler.external.mailto", true); // for mail diff --git a/browser/modules/PermissionUI.sys.mjs b/browser/modules/PermissionUI.sys.mjs @@ -72,6 +72,8 @@ ChromeUtils.defineESModuleGetters(lazy, { AddonManager: "resource://gre/modules/AddonManager.sys.mjs", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", SitePermissions: "resource:///modules/SitePermissions.sys.mjs", + clearTimeout: "resource://gre/modules/Timer.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", }); XPCOMUtils.defineLazyServiceGetter( @@ -112,6 +114,13 @@ XPCOMUtils.defineLazyPreferenceGetter( false ); +XPCOMUtils.defineLazyPreferenceGetter( + lazy, + "lnaPromptTimeoutMs", + "network.lna.prompt.timeout", + 300000 +); + /** * PermissionPrompt should be subclassed by callers that * want to display prompts to the user. See each method and property @@ -1009,18 +1018,88 @@ class XRPermissionPrompt extends PermissionPromptForRequest { } /** - * Creates a PermissionPrompt for a nsIContentPermissionRequest for - * the Local Host Access. + * Base class for Local Network Access (LNA) permission prompts. + * Provides automatic timeout handling for LNA prompts. * - * @param request (nsIContentPermissionRequest) - * The request for a permission from content. + * If the user doesn't respond to the prompt within the timeout period, + * the prompt is automatically cancelled and the network request fails. */ -class LocalHostPermissionPrompt extends PermissionPromptForRequest { +class LNAPermissionPromptBase extends PermissionPromptForRequest { + static DEFAULT_PROMPT_TIMEOUT_MS = 300000; + + #timeoutTimer = null; + constructor(request) { super(); this.request = request; } + onShown() { + this.#startTimeoutTimer(); + } + + onAfterShow() { + this.#clearTimeoutTimer(); + } + + cancel() { + super.cancel(); + } + + allow(choices) { + super.allow(choices); + } + + #startTimeoutTimer() { + this.#clearTimeoutTimer(); + + this.#timeoutTimer = lazy.setTimeout(() => { + let scriptError = Cc["@mozilla.org/scripterror;1"].createInstance( + Ci.nsIScriptError + ); + scriptError.initWithWindowID( + `LNA permission prompt timed out after ${lazy.lnaPromptTimeoutMs / 1000} seconds`, + null, + 0, + 0, + Ci.nsIScriptError.warningFlag, + "content javascript", + this.browser.browsingContext.currentWindowGlobal.innerWindowId + ); + Services.console.logMessage(scriptError); + + this.#removePrompt(); + this.cancel(); + }, lazy.lnaPromptTimeoutMs); + } + + #removePrompt() { + let chromeWin = this.browser?.ownerGlobal; + let notification = chromeWin?.PopupNotifications.getNotification( + this.notificationID, + this.browser + ); + if (notification) { + chromeWin.PopupNotifications.remove(notification); + } + } + + #clearTimeoutTimer() { + if (this.#timeoutTimer) { + lazy.clearTimeout(this.#timeoutTimer); + this.#timeoutTimer = null; + } + } +} + +/** + * Creates a PermissionPrompt for a nsIContentPermissionRequest for + * the Local Host Access. + * + * @param request (nsIContentPermissionRequest) + * The request for a permission from content. + */ +class LocalHostPermissionPrompt extends LNAPermissionPromptBase { get type() { return "localhost"; } @@ -1240,12 +1319,7 @@ class DesktopNotificationPermissionPrompt extends PermissionPromptForRequest { * @param request (nsIContentPermissionRequest) * The request for a permission from content. */ -class LocalNetworkPermissionPrompt extends PermissionPromptForRequest { - constructor(request) { - super(); - this.request = request; - } - +class LocalNetworkPermissionPrompt extends LNAPermissionPromptBase { get type() { return "local-network"; }