tor-browser

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

commit c1fbf0df4af5e490088e9e7f95b5b974666aa047
parent 52c2432a9e57d1d2292c09a56baaefd4a961706c
Author: Jack Brown <jbrown@mozilla.com>
Date:   Tue, 16 Dec 2025 17:38:23 +0000

Bug 1992401 - Add NS_ERROR_BASIC_HTTP_AUTH_DISABLED support to net-error-card - r=niklas,fluent-reviewers,flod

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

Diffstat:
Mbrowser/base/content/test/about/browser.toml | 2++
Abrowser/base/content/test/about/browser_aboutNetError_httpAuthDisabled.js | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/content/aboutNetError.mjs | 2+-
Mtoolkit/content/aboutNetErrorHelpers.mjs | 2++
Mtoolkit/content/net-error-card.mjs | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mtoolkit/locales/en-US/toolkit/neterror/netError.ftl | 5+++++
6 files changed, 187 insertions(+), 22 deletions(-)

diff --git a/browser/base/content/test/about/browser.toml b/browser/base/content/test/about/browser.toml @@ -68,6 +68,8 @@ support-files = [ "csp_iframe.sjs", ] +["browser_aboutNetError_httpAuthDisabled.js"] + ["browser_aboutNetError_internet_connection_offline.js"] ["browser_aboutNetError_invalid_header.js"] diff --git a/browser/base/content/test/about/browser_aboutNetError_httpAuthDisabled.js b/browser/base/content/test/about/browser_aboutNetError_httpAuthDisabled.js @@ -0,0 +1,75 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const BAD_CERT = "https://expired.example.com/"; + +// The revoked certificate page should not offer a proceed button. +add_task(async function checkHttpAuthDisabledCopy() { + await setSecurityCertErrorsFeltPrivacyToTrue(); + const tab = await openErrorPage(BAD_CERT); + const browser = tab.linkedBrowser; + + await SpecialPowers.spawn(browser, [], async function () { + const mockErrorInfo = { + errorCodeString: "NS_ERROR_BASIC_HTTP_AUTH_DISABLED", + channelStatus: 0, + errorMessage: "Unauthorized", + responseStatusText: "Unauthorized", + responseStatus: 401, + }; + + content.document.getFailedCertSecurityInfo = () => mockErrorInfo; + + const netErrorCard = + content.document.querySelector("net-error-card").wrappedJSObject; + const info = Cu.cloneInto(mockErrorInfo, netErrorCard); + netErrorCard.errorInfo = info; + netErrorCard.hideExceptionButton = netErrorCard.shouldHideExceptionButton( + info.errorCodeString + ); + netErrorCard.requestUpdate(); + await netErrorCard.getUpdateComplete(); + + const advancedButton = netErrorCard.advancedButton; + advancedButton.scrollIntoView(true); + EventUtils.synthesizeMouseAtCenter(advancedButton, {}, content); + + await ContentTaskUtils.waitForCondition( + () => netErrorCard.advancedContainer, + "Advanced section should be rendered for disabled HTTP auth." + ); + await ContentTaskUtils.waitForCondition( + () => netErrorCard.whyDangerous && netErrorCard.whatCanYouDo, + "Disabled HTTP auth copy should be rendered" + ); + + Assert.ok( + netErrorCard.advancedShowing, + "Advanced details are shown disabled HTTP auth." + ); + Assert.ok( + !netErrorCard.exceptionButton, + "Proceed button should not be shown for disabled HTTP auth." + ); + Assert.equal( + netErrorCard.whyDangerous.dataset.l10nId, + "fp-neterror-http-auth-disabled-why-dangerous-body", + "Using the 'http auth disabled' variant of the 'Why Dangerous' copy." + ); + Assert.equal( + netErrorCard.whatCanYouDo.dataset.l10nId, + "fp-neterror-http-auth-disabled-what-can-you-do-body", + "Using the 'http auth disabled' variant of the 'What can you do' copy." + ); + Assert.equal( + netErrorCard.learnMoreLink.dataset.l10nId, + "fp-learn-more-about-https-connections", + "'Learn more' link points to the HTTPS Connections page." + ); + }); + + BrowserTestUtils.removeTab(tab); + await SpecialPowers.popPrefEnv(); +}); diff --git a/toolkit/content/aboutNetError.mjs b/toolkit/content/aboutNetError.mjs @@ -21,6 +21,7 @@ import { errorHasNoUserFix, COOP_MDN_DOCS, COEP_MDN_DOCS, + HTTPS_UPGRADES_MDN_DOCS, } from "chrome://global/content/aboutNetErrorHelpers.mjs"; const formatter = new Intl.DateTimeFormat(); @@ -74,7 +75,6 @@ const KNOWN_ERROR_TITLE_IDS = new Set([ * aboutNetErrorCodes.js which is loaded before we are: */ /* global KNOWN_ERROR_MESSAGE_IDS */ const ERROR_MESSAGES_FTL = "toolkit/neterror/nsserrors.ftl"; -const HTTPS_UPGRADES_MDN_DOCS = "https://support.mozilla.org/kb/https-upgrades"; // If the location of the favicon changes, FAVICON_CERTERRORPAGE_URL and/or // FAVICON_ERRORPAGE_URL in toolkit/components/places/nsFaviconService.idl diff --git a/toolkit/content/aboutNetErrorHelpers.mjs b/toolkit/content/aboutNetErrorHelpers.mjs @@ -27,6 +27,8 @@ export const MDN_DOCS_HEADERS = "https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/"; export const COOP_MDN_DOCS = MDN_DOCS_HEADERS + "Cross-Origin-Opener-Policy"; export const COEP_MDN_DOCS = MDN_DOCS_HEADERS + "Cross-Origin-Embedder-Policy"; +export const HTTPS_UPGRADES_MDN_DOCS = + "https://support.mozilla.org/kb/https-upgrades"; export let gErrorCode = searchParams.get("e"); export let gIsCertError = gErrorCode == "nssBadCert"; export let gHasSts = gIsCertError && getCSSClass() === "badStsCert"; diff --git a/toolkit/content/net-error-card.mjs b/toolkit/content/net-error-card.mjs @@ -19,6 +19,7 @@ import { errorHasNoUserFix, COOP_MDN_DOCS, COEP_MDN_DOCS, + HTTPS_UPGRADES_MDN_DOCS, } from "chrome://global/content/aboutNetErrorHelpers.mjs"; import { html } from "chrome://global/content/vendor/lit.all.mjs"; import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; @@ -58,6 +59,7 @@ export class NetErrorCard extends MozLitElement { whyDangerous: "#fp-why-site-dangerous", netErrorTitleText: "#neterror-title-text", netErrorLearnMoreLink: "#neterror-learn-more-link", + httpAuthIntroText: "#fp-http-auth-disabled-intro-text", }; static ERROR_CODES = new Set([ @@ -74,8 +76,21 @@ export class NetErrorCard extends MozLitElement { "NS_ERROR_DOM_COOP_FAILED", "NS_ERROR_DOM_COEP_FAILED", "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE", + "NS_ERROR_BASIC_HTTP_AUTH_DISABLED", ]); + static CUSTOM_ERROR_CODES = { + blockedByCOOP: "NS_ERROR_DOM_COOP_FAILED", + blockedByCOEP: "NS_ERROR_DOM_COEP_FAILED", + basicHttpAuthDisabled: "NS_ERROR_BASIC_HTTP_AUTH_DISABLED", + }; + + static getCustomErrorCode(defaultCode) { + return gOffline + ? "NS_ERROR_OFFLINE" + : (NetErrorCard.CUSTOM_ERROR_CODES[defaultCode] ?? defaultCode); + } + static isSupported() { if (!FELT_PRIVACY_REFRESH) { return false; @@ -84,17 +99,10 @@ export class NetErrorCard extends MozLitElement { const errorInfo = gIsCertError ? document.getFailedCertSecurityInfo() : document.getNetErrorInfo(); - let errorCode = errorInfo.errorCodeString + const defaultErrorCode = errorInfo.errorCodeString ? errorInfo.errorCodeString : gErrorCode; - - if (gOffline) { - errorCode = "NS_ERROR_OFFLINE"; - } else if (gErrorCode === "blockedByCOOP") { - errorCode = "NS_ERROR_DOM_COOP_FAILED"; - } else if (gErrorCode === "blockedByCOEP") { - errorCode = "NS_ERROR_DOM_COEP_FAILED"; - } + const errorCode = NetErrorCard.getCustomErrorCode(defaultErrorCode); return NetErrorCard.ERROR_CODES.has(errorCode); } @@ -206,15 +214,7 @@ export class NetErrorCard extends MozLitElement { if (!errorInfo.errorCodeString) { this.showCustomNetErrorCard = true; - if (gOffline) { - errorInfo.errorCodeString = "NS_ERROR_OFFLINE"; - } else if (gErrorCode === "blockedByCOOP") { - errorInfo.errorCodeString = "NS_ERROR_DOM_COOP_FAILED"; - } else if (gErrorCode === "blockedByCOEP") { - errorInfo.errorCodeString = "NS_ERROR_DOM_COEP_FAILED"; - } - - errorInfo.errorCodeString = errorInfo.errorCodeString ?? gErrorCode; + errorInfo.errorCodeString = NetErrorCard.getCustomErrorCode(gErrorCode); } return errorInfo; } @@ -256,6 +256,17 @@ export class NetErrorCard extends MozLitElement { case "NS_ERROR_DOM_COOP_FAILED": case "NS_ERROR_DOM_COEP_FAILED": return html`<p data-l10n-id="fp-neterror-coop-coep-intro"></p>`; + case "NS_ERROR_BASIC_HTTP_AUTH_DISABLED": + return html`<p + id="fp-http-auth-disabled-intro-text" + data-l10n-id="fp-neterror-http-auth-disabled-intro" + ></p> + ${this.hideExceptionButton + ? html`<p + id="fp-http-auth-disabled-secure-connection-text" + data-l10n-id="fp-neterror-http-auth-disabled-secure-connection" + ></p> ` + : null} `; } return null; @@ -437,6 +448,20 @@ export class NetErrorCard extends MozLitElement { }); break; } + case "NS_ERROR_BASIC_HTTP_AUTH_DISABLED": { + content = this.advancedSectionTemplate({ + whyDangerousL10nId: + "fp-neterror-http-auth-disabled-why-dangerous-body", + whyDangerousL10nArgs: { + hostname: this.hostname, + }, + whatCanYouDoL10nId: + "fp-neterror-http-auth-disabled-what-can-you-do-body", + learnMoreL10nId: "fp-learn-more-about-https-connections", + learnMoreSupportPage: HTTPS_UPGRADES_MDN_DOCS, + }); + break; + } } return html`<div class="advanced-container"> @@ -575,6 +600,16 @@ export class NetErrorCard extends MozLitElement { }); break; } + case "NS_ERROR_BASIC_HTTP_AUTH_DISABLED": { + content = this.customNetErrorSectionTemplate({ + titleL10nId: "fp-certerror-body-title", + buttons: { + goBack: window.self === window.top, + }, + useAdvancedSection: true, + }); + break; + } } return html`<div class="custom-net-error-card">${content}</div>`; @@ -583,6 +618,8 @@ export class NetErrorCard extends MozLitElement { customNetErrorSectionTemplate(params) { const { titleL10nId, + whyDangerousL10nId, + whyDangerousL10nArgs, whyDidThisHappenL10nId, whyDidThisHappenL10nArgs, whatCanYouDoL10nId, @@ -590,12 +627,21 @@ export class NetErrorCard extends MozLitElement { learnMoreL10nId, learnMoreSupportPage, buttons = {}, + useAdvancedSection, } = params; const { goBack = false, tryAgain = false } = buttons; - return html`<h1 id="neterror-title-text" data-l10n-id=${titleL10nId}></h1> - ${this.introContentTemplate()} + const content = html` + ${whyDangerousL10nId + ? html`<p> + <strong data-l10n-id="fp-certerror-why-site-dangerous"></strong> + <span + data-l10n-id=${whyDangerousL10nId} + data-l10n-args=${JSON.stringify(whyDangerousL10nArgs)} + ></span> + </p>` + : null} ${whatCanYouDoL10nId ? html`<p> <strong data-l10n-id="fp-certerror-what-can-you-do"></strong> @@ -648,7 +694,42 @@ export class NetErrorCard extends MozLitElement { @click=${this.handleGoBackClick} ></moz-button ></moz-button-group>` - : null}`; + : null} + `; + + return html`<h1 id="neterror-title-text" data-l10n-id=${titleL10nId}></h1> + ${this.introContentTemplate()} + ${useAdvancedSection + ? html`<moz-button-group> + ${goBack + ? html`<moz-button + type="primary" + data-l10n-id="fp-certerror-return-to-previous-page-recommended-button" + data-telemetry-id="return_button_adv" + id="returnButton" + @click=${this.handleGoBackClick} + ></moz-button>` + : null} + ${tryAgain + ? html`<moz-button + id="tryAgainButton" + type="primary" + data-l10n-id="neterror-try-again-button" + data-telemetry-id="try_again_button" + @click=${this.handleTryAgain} + ></moz-button>` + : null} + <moz-button + id="advanced-button" + data-l10n-id=${this.advancedShowing + ? "fp-certerror-hide-advanced-button" + : "fp-certerror-advanced-button"} + data-telemetry-id="advanced_button" + @click=${this.toggleAdvancedShowing} + ></moz-button + ></moz-button-group>` + : content} + ${useAdvancedSection ? this.advancedContainerTemplate() : null} `; } async getDomainMismatchNames() { diff --git a/toolkit/locales/en-US/toolkit/neterror/netError.ftl b/toolkit/locales/en-US/toolkit/neterror/netError.ftl @@ -198,14 +198,19 @@ fp-neterror-offline-body-title = Looks like there’s a problem with your intern fp-neterror-connection-intro = { -brand-short-name } can’t create a secure connection to the server at { $hostname }. fp-neterror-offline-intro = { -brand-short-name } can’t connect to the server at <strong>{ $hostname }</strong> fp-neterror-coop-coep-intro = { -brand-short-name } didn’t load this page because it looks like the security configuration doesn’t match the previous page. +fp-neterror-http-auth-disabled-intro = Someone pretending to be the site could try to steal things like your username, password, or email. +fp-neterror-http-auth-disabled-secure-connection = This site requires a secure connection, and you can’t add an exception to visit it. fp-neterror-why-did-this-happen = Why did this happen? # This string appears after the following string: "What makes the site look dangerous?" (fp-certerror-why-site-dangerous) fp-neterror-cypher-overlap-why-dangerous-body = It looks like this site is using old software with known security issues. +fp-neterror-http-auth-disabled-why-dangerous-body = { -brand-short-name } doesn’t trust { $hostname } because the connection isn’t secure. # This string appears after the following string: "What can you do about it?" (fp-certerror-what-can-you-do) fp-neterror-cypher-overlap-what-can-you-do-body = Make sure you’re using the latest version of { -brand-short-name }. Go to Help > About { -brand-short-name } in the menu. If you’re using the latest { -brand-short-name }, the problem is most likely with the site itself. fp-neterror-offline-what-can-you-do-body = Try connecting on a different device. Check your modem or router. Disconnect and reconnect to Wi-Fi. +fp-neterror-http-auth-disabled-what-can-you-do-body = Try changing the URL to HTTPS. But it’s likely there’s a problem with the site itself. # This string appears after the following string: "Why did this happen?" (fp-neterror-why-did-this-happen) fp-neterror-coop-coep-why-did-this-happen-body = Sometimes websites set up protections for themselves from unwanted interactions with other sites. +fp-learn-more-about-https-connections = Learn about HTTPS connections