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:
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