diff --git a/toolkit/actors/NetErrorChild.jsm b/toolkit/actors/NetErrorChild.jsm index 14a7a5bd4da0..d91c84b79bf9 100644 --- a/toolkit/actors/NetErrorChild.jsm +++ b/toolkit/actors/NetErrorChild.jsm @@ -29,7 +29,8 @@ class NetErrorChild extends RemotePageChild { "RPMCheckAlternateHostAvailable", "RPMGetHttpResponseHeader", "RPMIsTRROnlyFailure", - "RPMShowTRROnlyFailureError", + "RPMIsFirefox", + "RPMIsNativeFallbackFailure", "RPMOpenPreferences", "RPMGetTRRSkipReason", "RPMGetTRRDomain", @@ -162,7 +163,7 @@ class NetErrorChild extends RemotePageChild { } RPMIsTRROnlyFailure() { - // As per RPMShowTRROnlyFailureError, we will only show this in Firefox + // We will only show this in Firefox because the options may direct users to settings only available on Firefox Desktop let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface( Ci.nsIHttpChannelInternal ); @@ -172,10 +173,37 @@ class NetErrorChild extends RemotePageChild { return channel.effectiveTRRMode == Ci.nsIRequest.TRR_ONLY_MODE; } - RPMShowTRROnlyFailureError() { + RPMIsFirefox() { return lazy.AppInfo.isFirefox; } + RPMIsNativeFallbackFailure() { + let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface( + Ci.nsIHttpChannelInternal + ); + let value = channel?.trrSkipReason ?? Ci.nsITRRSkipReason.TRR_UNSET; + + const warningReasons = new Set([ + Ci.nsITRRSkipReason.TRR_NOT_CONFIRMED, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_CANARY, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_VPN, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PROXY, + Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_NRPT, + ]); + + return ( + Services.dns.currentTrrMode == Ci.nsIRequest.TRR_FIRST_MODE && + warningReasons.has(value) + ); + } + RPMGetTRRSkipReason() { let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface( Ci.nsIHttpChannelInternal diff --git a/toolkit/content/aboutNetError.mjs b/toolkit/content/aboutNetError.mjs index 62cdc8a86c49..b2aa548cdcc2 100644 --- a/toolkit/content/aboutNetError.mjs +++ b/toolkit/content/aboutNetError.mjs @@ -239,6 +239,12 @@ function initPage() { const isTRROnlyFailure = gErrorCode == "dnsNotFound" && RPMIsTRROnlyFailure(); + let isNativeFallbackWarning = false; + if (RPMGetBoolPref("network.trr.display_fallback_warning")) { + isNativeFallbackWarning = + gErrorCode == "dnsNotFound" && RPMIsNativeFallbackFailure(); + } + const docTitle = document.querySelector("title"); const bodyTitle = document.querySelector(".title-text"); const shortDesc = document.getElementById("errorShortDesc"); @@ -390,90 +396,99 @@ function initPage() { bodyTitleId = "generic-title"; } - if (isTRROnlyFailure && RPMShowTRROnlyFailureError()) { - document.body.className = "certerror"; // Shows warning icon - pageTitleId = "dns-not-found-trr-only-title"; - document.l10n.setAttributes(docTitle, pageTitleId, { - hostname: HOST_NAME, - }); - bodyTitleId = "dns-not-found-trr-only-title"; - document.l10n.setAttributes(bodyTitle, bodyTitleId, { - hostname: HOST_NAME, - }); - - shortDesc.textContent = ""; - - // enable buttons - let trrExceptionButton = document.getElementById("trrExceptionButton"); - trrExceptionButton.addEventListener("click", () => { - RPMSendQuery("Browser:AddTRRExcludedDomain", { + // The TRR errors may present options that direct users to settings only available on Firefox Desktop + if (RPMIsFirefox()) { + if (isTRROnlyFailure) { + document.body.className = "certerror"; // Shows warning icon + pageTitleId = "dns-not-found-trr-only-title"; + document.l10n.setAttributes(docTitle, pageTitleId, { hostname: HOST_NAME, - }).then(msg => { - retryThis(this); }); - }); - trrExceptionButton.hidden = false; - let trrSettingsButton = document.getElementById("trrSettingsButton"); - trrSettingsButton.addEventListener("click", () => { - RPMSendAsyncMessage("OpenTRRPreferences"); - }); - trrSettingsButton.hidden = false; - let message = document.getElementById("trrOnlyMessage"); - document.l10n.setAttributes( - message, - "neterror-dns-not-found-trr-only-reason", - { + bodyTitleId = "dns-not-found-trr-only-title"; + document.l10n.setAttributes(bodyTitle, bodyTitleId, { hostname: HOST_NAME, + }); + + shortDesc.textContent = ""; + + // enable buttons + let trrExceptionButton = document.getElementById("trrExceptionButton"); + trrExceptionButton.addEventListener("click", () => { + RPMSendQuery("Browser:AddTRRExcludedDomain", { + hostname: HOST_NAME, + }).then(msg => { + retryThis(this); + }); + }); + trrExceptionButton.hidden = false; + let trrSettingsButton = document.getElementById("trrSettingsButton"); + trrSettingsButton.addEventListener("click", () => { + RPMSendAsyncMessage("OpenTRRPreferences"); + }); + trrSettingsButton.hidden = false; + let message = document.getElementById("trrOnlyMessage"); + document.l10n.setAttributes( + message, + "neterror-dns-not-found-trr-only-reason", + { + hostname: HOST_NAME, + } + ); + + let skipReason = RPMGetTRRSkipReason(); + + let descriptionTag = "neterror-dns-not-found-trr-unknown-problem"; + let args = { trrDomain: RPMGetTRRDomain() }; + if ( + skipReason == "TRR_FAILED" || + skipReason == "TRR_CHANNEL_DNS_FAIL" || + skipReason == "TRR_UNKNOWN_CHANNEL_FAILURE" || + skipReason == "TRR_NET_REFUSED" || + skipReason == "TRR_NET_INTERRUPT" || + skipReason == "TRR_NET_INADEQ_SEQURITY" + ) { + descriptionTag = "neterror-dns-not-found-trr-only-could-not-connect"; + } else if (skipReason == "TRR_TIMEOUT") { + descriptionTag = "neterror-dns-not-found-trr-only-timeout"; + } else if ( + skipReason == "TRR_IS_OFFLINE" || + skipReason == "TRR_NO_CONNECTIVITY" + ) { + descriptionTag = "neterror-dns-not-found-trr-offline"; + } else if ( + skipReason == "TRR_NO_ANSWERS" || + skipReason == "TRR_NXDOMAIN" + ) { + descriptionTag = "neterror-dns-not-found-trr-unknown-host"; + } else if ( + skipReason == "TRR_DECODE_FAILED" || + skipReason == "TRR_SERVER_RESPONSE_ERR" + ) { + descriptionTag = "neterror-dns-not-found-trr-server-problem"; } - ); - let skipReason = RPMGetTRRSkipReason(); + let description = document.getElementById("trrOnlyDescription"); + document.l10n.setAttributes(description, descriptionTag, args); - let descriptionTag = "neterror-dns-not-found-trr-unknown-problem"; - let args = { trrDomain: RPMGetTRRDomain() }; - if ( - skipReason == "TRR_FAILED" || - skipReason == "TRR_CHANNEL_DNS_FAIL" || - skipReason == "TRR_UNKNOWN_CHANNEL_FAILURE" || - skipReason == "TRR_NET_REFUSED" || - skipReason == "TRR_NET_INTERRUPT" || - skipReason == "TRR_NET_INADEQ_SEQURITY" - ) { - descriptionTag = "neterror-dns-not-found-trr-only-could-not-connect"; - } else if (skipReason == "TRR_TIMEOUT") { - descriptionTag = "neterror-dns-not-found-trr-only-timeout"; - } else if ( - skipReason == "TRR_IS_OFFLINE" || - skipReason == "TRR_NO_CONNECTIVITY" - ) { - descriptionTag = "neterror-dns-not-found-trr-offline"; - } else if (skipReason == "TRR_NO_ANSWERS" || skipReason == "TRR_NXDOMAIN") { - descriptionTag = "neterror-dns-not-found-trr-unknown-host"; - } else if ( - skipReason == "TRR_DECODE_FAILED" || - skipReason == "TRR_SERVER_RESPONSE_ERR" - ) { - descriptionTag = "neterror-dns-not-found-trr-server-problem"; + const trrLearnMoreContainer = document.getElementById( + "trrLearnMoreContainer" + ); + trrLearnMoreContainer.hidden = false; + let learnMoreLink = document.getElementById("trrOnlylearnMoreLink"); + // This will be replaced at a later point with a link to an offline support page + // https://bugzilla.mozilla.org/show_bug.cgi?id=1806257 + learnMoreLink.href = + RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") + + skipReason.toLowerCase().replaceAll("_", "-"); + + let div = document.getElementById("trrOnlyContainer"); + div.hidden = false; + + return; + } else if (isNativeFallbackWarning) { + showNativeFallbackWarning(); + return; } - - let description = document.getElementById("trrOnlyDescription"); - document.l10n.setAttributes(description, descriptionTag, args); - - const trrLearnMoreContainer = document.getElementById( - "trrLearnMoreContainer" - ); - trrLearnMoreContainer.hidden = false; - let learnMoreLink = document.getElementById("trrOnlylearnMoreLink"); - // This will be replaced at a later point with a link to an offline support page - // https://bugzilla.mozilla.org/show_bug.cgi?id=1806257 - learnMoreLink.href = - RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") + - skipReason.toLowerCase().replaceAll("_", "-"); - - let div = document.getElementById("trrOnlyContainer"); - div.hidden = false; - - return; } document.l10n.setAttributes(docTitle, pageTitleId); @@ -490,6 +505,69 @@ function initPage() { setNetErrorMessageFromCode(); } +function showNativeFallbackWarning() { + const docTitle = document.querySelector("title"); + const bodyTitle = document.querySelector(".title-text"); + const shortDesc = document.getElementById("errorShortDesc"); + + let pageTitleId = "neterror-page-title"; + let bodyTitleId = gErrorCode + "-title"; + + document.body.className = "certerror"; // Shows warning icon + pageTitleId = "dns-not-found-native-fallback-title"; + document.l10n.setAttributes(docTitle, pageTitleId, { + hostname: HOST_NAME, + }); + + bodyTitleId = "dns-not-found-native-fallback-title"; + document.l10n.setAttributes(bodyTitle, bodyTitleId, { + hostname: HOST_NAME, + }); + + shortDesc.textContent = ""; + let nativeFallbackIgnoreButton = document.getElementById( + "nativeFallbackIgnoreButton" + ); + nativeFallbackIgnoreButton.addEventListener("click", () => { + RPMSetBoolPref("network.trr.display_fallback_warning", false); + retryThis(nativeFallbackIgnoreButton); + }); + + nativeFallbackIgnoreButton.hidden = false; + let message = document.getElementById("nativeFallbackMessage"); + document.l10n.setAttributes( + message, + "neterror-dns-not-found-native-fallback-reason", + { + hostname: HOST_NAME, + } + ); + let skipReason = RPMGetTRRSkipReason(); + let descriptionTag = "neterror-dns-not-found-trr-unknown-problem"; + let args = { trrDomain: RPMGetTRRDomain() }; + + if (skipReason.includes("HEURISTIC_TRIPPED")) { + descriptionTag = "neterror-dns-not-found-native-fallback-heuristic"; + } else if (skipReason == "TRR_NOT_CONFIRMED") { + descriptionTag = "neterror-dns-not-found-native-fallback-not-confirmed"; + } + + let description = document.getElementById("nativeFallbackDescription"); + document.l10n.setAttributes(description, descriptionTag, args); + + let learnMoreContainer = document.getElementById( + "nativeFallbackLearnMoreContainer" + ); + learnMoreContainer.hidden = false; + + let learnMoreLink = document.getElementById("nativeFallbackLearnMoreLink"); + learnMoreLink.href = + RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") + + skipReason.toLowerCase().replaceAll("_", "-"); + + let div = document.getElementById("nativeFallbackContainer"); + div.hidden = false; +} /** * Builds HTML elements from `parts` and appends them to `parent`. * diff --git a/toolkit/content/aboutNetError.xhtml b/toolkit/content/aboutNetError.xhtml index 4b5172efea72..8ca1be38da7f 100644 --- a/toolkit/content/aboutNetError.xhtml +++ b/toolkit/content/aboutNetError.xhtml @@ -51,6 +51,17 @@

+

+
+ + +
+

+

+
diff --git a/toolkit/locales/en-US/toolkit/neterror/certError.ftl b/toolkit/locales/en-US/toolkit/neterror/certError.ftl index 60e2f8e20517..9f4880ca7530 100644 --- a/toolkit/locales/en-US/toolkit/neterror/certError.ftl +++ b/toolkit/locales/en-US/toolkit/neterror/certError.ftl @@ -110,6 +110,11 @@ dnsNotFound-title = Hmm. We’re having trouble finding that site. dns-not-found-trr-only-title = Possible security risk for { $hostname }. +# Variables: +# $hostname (String) - Hostname of the website to which the user was trying to connect. +dns-not-found-native-fallback-title = + Possible security risk for { $hostname }. + fileNotFound-title = File not found fileAccessDenied-title = Access to the file was denied generic-title = Oops. diff --git a/toolkit/locales/en-US/toolkit/neterror/netError.ftl b/toolkit/locales/en-US/toolkit/neterror/netError.ftl index 5a238c284dfd..06bda7217377 100644 --- a/toolkit/locales/en-US/toolkit/neterror/netError.ftl +++ b/toolkit/locales/en-US/toolkit/neterror/netError.ftl @@ -26,6 +26,7 @@ neterror-try-again-button = Try Again neterror-add-exception-button = Always continue for this site neterror-settings-button = Change DNS settings neterror-view-certificate-link = View Certificate +neterror-disable-native-feedback-warning = Always continue ## @@ -65,6 +66,15 @@ neterror-dns-not-found-trr-unknown-host = An address for this website wasn’t f neterror-dns-not-found-trr-server-problem = There was a problem with { $trrDomain }. neterror-dns-not-found-trr-unknown-problem = Unexpected problem. +## Native fallback specific messages +## Variables: +## $trrDomain (String) - Hostname of the DNS over HTTPS server that is currently in use. + +neterror-dns-not-found-native-fallback-reason = { -brand-short-name } can’t protect your request for this site’s address through our trusted DNS resolver. Here’s why: +neterror-dns-not-found-native-fallback-attackers = You can continue with a DNS resolver that is not secure. However, a third-party might be able to see what websites you visit or send you to an untrusted site. +neterror-dns-not-found-native-fallback-heuristic = DNS over HTTPs has been disabled on your network. +neterror-dns-not-found-native-fallback-not-confirmed = The connection to { $trrDomain } isn’t ready yet. + ## neterror-file-not-found-filename = Check the file name for capitalization or other typing errors. diff --git a/toolkit/modules/AsyncPrefs.sys.mjs b/toolkit/modules/AsyncPrefs.sys.mjs index f5adf11b6002..583c0af1774f 100644 --- a/toolkit/modules/AsyncPrefs.sys.mjs +++ b/toolkit/modules/AsyncPrefs.sys.mjs @@ -55,6 +55,8 @@ const kAllowedPrefs = new Set([ "security.tls.version.enable-deprecated", "security.xfocsp.errorReporting.automatic", + + "network.trr.display_fallback_warning", ]); const kPrefTypeMap = new Map([ diff --git a/toolkit/modules/RemotePageAccessManager.sys.mjs b/toolkit/modules/RemotePageAccessManager.sys.mjs index cc3cc8c42e5a..3078644a450f 100644 --- a/toolkit/modules/RemotePageAccessManager.sys.mjs +++ b/toolkit/modules/RemotePageAccessManager.sys.mjs @@ -48,6 +48,7 @@ export let RemotePageAccessManager = { "security.certerrors.permanentOverride", "security.enterprise_roots.auto-enabled", "security.certerror.hideAddException", + "network.trr.display_fallback_warning", ], RPMGetIntPref: [ "services.settings.clock_skew_seconds", @@ -92,13 +93,18 @@ export let RemotePageAccessManager = { "security.certerror.hideAddException", "security.xfocsp.errorReporting.automatic", "security.xfocsp.errorReporting.enabled", + "network.trr.display_fallback_warning", + ], + RPMSetBoolPref: [ + "security.xfocsp.errorReporting.automatic", + "network.trr.display_fallback_warning", ], - RPMSetBoolPref: ["security.xfocsp.errorReporting.automatic"], RPMAddToHistogram: ["*"], RPMGetInnerMostURI: ["*"], RPMGetHttpResponseHeader: ["*"], RPMIsTRROnlyFailure: ["*"], - RPMShowTRROnlyFailureError: ["*"], + RPMIsFirefox: ["*"], + RPMIsNativeFallbackFailure: ["*"], RPMGetTRRSkipReason: ["*"], RPMGetTRRDomain: ["*"], RPMSendQuery: ["Browser:AddTRRExcludedDomain"], diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js index 0adebe90bcfc..a6df3c31530c 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/remote-page.js @@ -21,7 +21,8 @@ module.exports = { RPMSetBoolPref: false, RPMGetFormatURLPref: false, RPMIsTRROnlyFailure: false, - RPMShowTRROnlyFailureError: false, + RPMIsFirefox: false, + RPMIsNativeFallbackFailure: false, RPMIsWindowPrivate: false, RPMSendAsyncMessage: false, RPMSendQuery: false,