From 82a4475a6afe48638f37c06b484d6cf0d5adf2ca Mon Sep 17 00:00:00 2001 From: prathiksha Date: Wed, 26 Jun 2019 20:24:05 +0000 Subject: [PATCH] Bug 1555438 - Remove getDetailedCertErrorInfo from NetErrorChild.jsm. r=johannh,fluent-reviewers,flod Differential Revision: https://phabricator.services.mozilla.com/D33065 --HG-- extra : moz-landing-system : lando --- browser/actors/NetErrorChild.jsm | 52 ++++-------- browser/base/content/aboutNetError.js | 83 ++++++++++++++----- browser/base/content/browser.js | 73 ---------------- ...browser_aboutCertError_noSubjectAltName.js | 7 +- browser/components/BrowserGlue.jsm | 3 - .../locales/en-US/browser/aboutCertError.ftl | 9 ++ .../en-US/chrome/browser/browser.properties | 7 -- .../bug_1555438_aboutCertError.py | 48 +++++++++++ .../remotepagemanager/MessagePort.jsm | 12 ++- 9 files changed, 148 insertions(+), 146 deletions(-) create mode 100644 python/l10n/fluent_migrations/bug_1555438_aboutCertError.py diff --git a/browser/actors/NetErrorChild.jsm b/browser/actors/NetErrorChild.jsm index cb5a5db3a09f..6e67712bf8d7 100644 --- a/browser/actors/NetErrorChild.jsm +++ b/browser/actors/NetErrorChild.jsm @@ -67,7 +67,7 @@ class NetErrorChild extends ActorChild { switch (aEvent.type) { case "AboutNetErrorLoad": - this.onPageLoad(aEvent.originalTarget, doc.defaultView); + this.onPageLoad(doc.defaultView); break; case "AboutNetErrorSetAutomatic": this.onSetAutomatic(aEvent); @@ -90,22 +90,6 @@ class NetErrorChild extends ActorChild { } } - receiveMessage(msg) { - if (msg.name == "CertErrorDetails") { - let frameDocShell = WebNavigationFrames.findDocShell(msg.data.frameId, this.docShell); - // We need nsIWebNavigation to access docShell.document. - frameDocShell && frameDocShell.QueryInterface(Ci.nsIWebNavigation); - if (!frameDocShell || !this.isAboutCertError(frameDocShell.document)) { - return; - } - - let data = msg.data; - let win = frameDocShell.document.ownerGlobal; - let event = Cu.cloneInto({ detail: data }, win); - win.dispatchEvent(new win.CustomEvent("ShowCertErrorDetails", event)); - } - } - changedCertPrefs() { let prefSSLImpact = PREF_SSL_IMPACT_ROOTS.reduce((prefs, root) => { return prefs.concat(Services.prefs.getChildList(root)); @@ -165,17 +149,10 @@ class NetErrorChild extends ActorChild { return msg; } - onPageLoad(originalTarget, win) { + onPageLoad(win) { // Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0; - let hideAddExceptionButton = false; - - if (this.isAboutCertError(win.document)) { - this.onCertError(originalTarget, win); - hideAddExceptionButton = - Services.prefs.getBoolPref("security.certerror.hideAddException", false); - } if (this.isAboutNetError(win.document)) { let docShell = win.docShell; if (docShell) { @@ -193,20 +170,19 @@ class NetErrorChild extends ActorChild { let learnMoreLink = win.document.getElementById("learnMoreLink"); let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); learnMoreLink.setAttribute("href", baseURL + "connection-not-secure"); + + let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic"); + win.dispatchEvent(new win.CustomEvent("AboutNetErrorOptions", { + detail: JSON.stringify({ + enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"), + changedCertPrefs: this.changedCertPrefs(), + automatic, + }), + })); + + this.mm.sendAsyncMessage("Browser:SSLErrorReportTelemetry", + {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN}); } - - let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic"); - win.dispatchEvent(new win.CustomEvent("AboutNetErrorOptions", { - detail: JSON.stringify({ - enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"), - changedCertPrefs: this.changedCertPrefs(), - automatic, - hideAddExceptionButton, - }), - })); - - this.mm.sendAsyncMessage("Browser:SSLErrorReportTelemetry", - {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN}); } onResetPreferences(evt) { diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js index 24420a69f3a0..e38e37a33793 100644 --- a/browser/base/content/aboutNetError.js +++ b/browser/base/content/aboutNetError.js @@ -349,19 +349,16 @@ function initPageCertError() { })); }); - addEventListener("AboutNetErrorOptions", function(event) { - var options = JSON.parse(event.detail); - if (options && options.enabled) { - // Display error reporting UI - document.getElementById("certificateErrorReporting").style.display = "block"; - - // set the checkbox - checkbox.checked = !!options.automatic; - } - if (options && options.hideAddExceptionButton) { - document.querySelector(".exceptionDialogButtonContainer").hidden = true; - } - }, true, true); + let errorReportingEnabled = RPMGetBoolPref("security.ssl.errorReporting.enabled"); + if (errorReportingEnabled) { + document.getElementById("certificateErrorReporting").style.display = "block"; + let errorReportingAutomatic = RPMGetBoolPref("security.ssl.errorReporting.automatic"); + checkbox.checked = !!errorReportingAutomatic; + } + let hideAddExceptionButton = RPMGetBoolPref("security.certerror.hideAddException"); + if (hideAddExceptionButton) { + document.querySelector(".exceptionDialogButtonContainer").hidden = true; + } let failedCertInfo = document.getFailedCertSecurityInfo(); RPMSendAsyncMessage("RecordCertErrorLoad", { @@ -370,14 +367,60 @@ function initPageCertError() { has_sts: getCSSClass() == "badStsCert", is_frame: window.parent != window, }); - window.addEventListener("ShowCertErrorDetails", setCertErrorDetails); + + let certErrorButtons = ["advancedButton", "copyToClipboard"]; + for (let button of certErrorButtons) { + let elem = document.getElementById(button); + elem.addEventListener("click", onClickHandler); + } + + setCertErrorDetails(); setTechnicalDetailsOnCertError(); + // Dispatch this event only for tests. let event = new CustomEvent("AboutNetErrorLoad", {bubbles: true}); - document.getElementById("advancedButton").dispatchEvent(event); + document.dispatchEvent(event); } -function setCertErrorDetails(event) { +async function onClickHandler(e) { + switch (e.target.id) { + case "advancedButton": + setCertErrorDetails(); + break; + case "copyToClipboard": + let details = await getCertErrorInfo(); + navigator.clipboard.writeText(details); + break; + } +} + +async function getCertErrorInfo() { + let location = document.location.href; + let failedCertInfo = document.getFailedCertSecurityInfo(); + let errorMessage = failedCertInfo.errorMessage; + let hasHSTS = failedCertInfo.hasHSTS.toString(); + let hasHPKP = failedCertInfo.hasHPKP.toString(); + let [hstsLabel] = + await document.l10n.formatValues([{id: "cert-error-details-hsts-label", args: { hasHSTS }}]); + let [hpkpLabel] = + await document.l10n.formatValues([{id: "cert-error-details-key-pinning-label", args: { hasHPKP }}]); + + let certStrings = failedCertInfo.certChainStrings; + let failedChainCertificates = ""; + for (let der64 of certStrings) { + let wrapped = der64.replace(/(\S{64}(?!$))/g, "$1\r\n"); + failedChainCertificates += "-----BEGIN CERTIFICATE-----\r\n" + + wrapped + + "\r\n-----END CERTIFICATE-----\r\n"; + } + let [failedChainLabel] = await document.l10n.formatValues([{id: "cert-error-details-cert-chain-label"}]); + + let details = location + "\r\n\r\n" + errorMessage + "\r\n\r\n" + hstsLabel + "\r\n" + hpkpLabel + + "\r\n\r\n" + failedChainLabel + "\r\n\r\n" + failedChainCertificates; + return details; +} + +async function setCertErrorDetails(event) { // Check if the connection is being man-in-the-middled. When the parent // detects an intercepted connection, the page may be reloaded with a new // error code (MOZILLA_PKIX_ERROR_MITM_DETECTED). @@ -391,7 +434,7 @@ function setCertErrorDetails(event) { } let div = document.getElementById("certificateErrorText"); - div.textContent = event.detail.info; + div.textContent = await getCertErrorInfo(); let learnMoreLink = document.getElementById("learnMoreLink"); let baseURL = RPMGetFormatURLPref("app.support.baseURL"); learnMoreLink.setAttribute("href", baseURL + "connection-not-secure"); @@ -499,8 +542,8 @@ function setCertErrorDetails(event) { learnMoreLink.href = baseURL + "time-errors"; // We check against the remote-settings server time first if available, because that allows us // to give the user an approximation of what the correct time is. - let difference = event.detail.clockSkewDifference; - let lastFetched = event.detail.settingsLastFetched * 1000; + let difference = RPMGetIntPref("services.settings.clock_skew_seconds"); + let lastFetched = RPMGetIntPref("services.settings.last_update_seconds") * 1000; let now = Date.now(); let certRange = { @@ -516,7 +559,7 @@ function setCertErrorDetails(event) { // If there is no clock skew with Kinto servers, check against the build date. // (The Kinto ping could have happened when the time was still right, or not at all) } else { - let appBuildID = event.detail.appBuildID; + let appBuildID = RPMGetAppBuildID(); let year = parseInt(appBuildID.substr(0, 4), 10); let month = parseInt(appBuildID.substr(4, 2), 10) - 1; let day = parseInt(appBuildID.substr(6, 2), 10); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 4a763189d4a2..013426f262ac 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3145,31 +3145,6 @@ var BrowserOnClick = { case "advancedPanelReturnButton": goBackFromErrorPage(); break; - - case "advancedButton": - securityInfo = getSecurityInfo(securityInfoAsString); - let errorInfo = getDetailedCertErrorInfo(location, - securityInfo); - let clockSkewDifference = Services.prefs.getIntPref("services.settings.clock_skew_seconds", 0); - let settingsLastFetched = Services.prefs.getIntPref("services.settings.last_update_seconds", 0); - let appBuildID = Services.appinfo.appBuildID; - browser.messageManager.sendAsyncMessage("CertErrorDetails", { - info: errorInfo, - clockSkewDifference, - settingsLastFetched, - appBuildID, - frameId, - }); - break; - - case "copyToClipboard": - const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"] - .getService(Ci.nsIClipboardHelper); - securityInfo = getSecurityInfo(securityInfoAsString); - let detailedInfo = getDetailedCertErrorInfo(location, - securityInfo); - gClipboardHelper.copyString(detailedInfo); - break; } }, @@ -3417,54 +3392,6 @@ function getSecurityInfo(securityInfoAsString) { return securityInfo; } -/** - * Returns a string with detailed information about the certificate validation - * failure from the specified URI that can be used to send a report. - */ -function getDetailedCertErrorInfo(location, securityInfo) { - if (!securityInfo) - return ""; - - let certErrorDetails = location; - let code = securityInfo.errorCode; - let errors = Cc["@mozilla.org/nss_errors_service;1"] - .getService(Ci.nsINSSErrorsService); - - certErrorDetails += "\r\n\r\n" + errors.getErrorMessage(errors.getXPCOMFromNSSError(code)); - - const sss = Cc["@mozilla.org/ssservice;1"] - .getService(Ci.nsISiteSecurityService); - // SiteSecurityService uses different storage if the channel is - // private. Thus we must give isSecureURI correct flags or we - // might get incorrect results. - let flags = PrivateBrowsingUtils.isWindowPrivate(window) ? - Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0; - - let uri = Services.io.newURI(location); - - let hasHSTS = sss.isSecureURI(sss.HEADER_HSTS, uri, flags); - let hasHPKP = sss.isSecureURI(sss.HEADER_HPKP, uri, flags); - certErrorDetails += "\r\n\r\n" + - gNavigatorBundle.getFormattedString("certErrorDetailsHSTS.label", - [hasHSTS]); - certErrorDetails += "\r\n" + - gNavigatorBundle.getFormattedString("certErrorDetailsKeyPinning.label", - [hasHPKP]); - - let certChain = ""; - if (securityInfo.failedCertChain) { - for (let cert of securityInfo.failedCertChain.getEnumerator()) { - certChain += getPEMString(cert); - } - } - - certErrorDetails += "\r\n\r\n" + - gNavigatorBundle.getString("certErrorDetailsCertChain.label") + - "\r\n\r\n" + certChain; - - return certErrorDetails; -} - // TODO: can we pull getDERString and getPEMString in from pippki.js instead of // duplicating them here? function getDERString(cert) { diff --git a/browser/base/content/test/about/browser_aboutCertError_noSubjectAltName.js b/browser/base/content/test/about/browser_aboutCertError_noSubjectAltName.js index 2abeccd86fd8..9ef810f3d263 100644 --- a/browser/base/content/test/about/browser_aboutCertError_noSubjectAltName.js +++ b/browser/base/content/test/about/browser_aboutCertError_noSubjectAltName.js @@ -20,8 +20,11 @@ const checkAdvancedAndGetTechnicalInfoText = async () => { let badCertTechnicalInfo = doc.getElementById("badCertTechnicalInfo"); ok(badCertTechnicalInfo, "badCertTechnicalInfo found"); - let errorCode = doc.getElementById("errorCode").innerHTML; - is(errorCode, "SSL_ERROR_BAD_CERT_DOMAIN"); + // Wait until fluent sets the errorCode inner text. + await ContentTaskUtils.waitForCondition(() => { + let errorCode = doc.getElementById("errorCode"); + return errorCode.textContent == "SSL_ERROR_BAD_CERT_DOMAIN"; + }, "correct error code has been set inside the advanced button panel"); let viewCertificate = doc.getElementById("viewCertificate"); ok(viewCertificate, "viewCertificate found"); diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index f29118156f72..fc7ac27fa705 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -232,9 +232,6 @@ let LEGACY_ACTORS = { }, matches: ["about:certerror?*", "about:neterror?*"], allFrames: true, - messages: [ - "CertErrorDetails", - ], }, }, diff --git a/browser/locales/en-US/browser/aboutCertError.ftl b/browser/locales/en-US/browser/aboutCertError.ftl index ea48c9c6991a..05635df05680 100644 --- a/browser/locales/en-US/browser/aboutCertError.ftl +++ b/browser/locales/en-US/browser/aboutCertError.ftl @@ -70,3 +70,12 @@ cert-error-symantec-distrust-description = Websites prove their identity via cer cert-error-symantec-distrust-admin = You may notify the website’s administrator about this problem. +# Variables: +# $hasHSTS (Boolean) - Indicates whether HSTS header is present. +cert-error-details-hsts-label = HTTP Strict Transport Security: { $hasHSTS } + +# Variables: +# $hasHPKP (Boolean) - Indicates whether HPKP header is present. +cert-error-details-key-pinning-label = HTTP Public Key Pinning: { $hasHPKP } + +cert-error-details-cert-chain-label = Certificate chain: diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index 8fc5127fe6ae..609734ed3d28 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -999,13 +999,6 @@ sendTabsToDevice.accesskey = n # #1 is the number of tabs sent to the device. pageAction.sendTabsToDevice.label = Send Tab to Device;Send #1 Tabs to Device -# LOCALIZATION NOTE (certErrorDetails*.label): These are text strings that -# appear in the about:certerror page, so that the user can copy and send them to -# the server administrators for troubleshooting. -certErrorDetailsHSTS.label = HTTP Strict Transport Security: %S -certErrorDetailsKeyPinning.label = HTTP Public Key Pinning: %S -certErrorDetailsCertChain.label = Certificate chain: - # LOCALIZATION NOTE (pendingCrashReports2.label): Semi-colon list of plural forms # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals # #1 is the number of pending crash reports diff --git a/python/l10n/fluent_migrations/bug_1555438_aboutCertError.py b/python/l10n/fluent_migrations/bug_1555438_aboutCertError.py new file mode 100644 index 000000000000..2537a81a945b --- /dev/null +++ b/python/l10n/fluent_migrations/bug_1555438_aboutCertError.py @@ -0,0 +1,48 @@ +# coding=utf8 + +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +from __future__ import absolute_import +import fluent.syntax.ast as FTL +from fluent.migrate.helpers import transforms_from +from fluent.migrate.helpers import VARIABLE_REFERENCE +from fluent.migrate import COPY, REPLACE + +def migrate(ctx): + """Bug 1555438 - Migrate strings from pipnss.properties to aboutCertError.ftl""" + ctx.add_transforms( + 'browser/browser/aboutCertError.ftl', + 'browser/browser/aboutCertError.ftl', + [ + FTL.Message( + id=FTL.Identifier('cert-error-details-hsts-label'), + value=REPLACE( + 'browser/chrome/browser/browser.properties', + 'certErrorDetailsHSTS.label', + { + "%1$S": VARIABLE_REFERENCE("hasHSTS"), + }, + normalize_printf=True + ), + ), + FTL.Message( + id=FTL.Identifier('cert-error-details-key-pinning-label'), + value=REPLACE( + 'browser/chrome/browser/browser.properties', + 'certErrorDetailsKeyPinning.label', + { + "%1$S": VARIABLE_REFERENCE("hasHPKP"), + }, + normalize_printf=True + ), + ), + ] + ) + ctx.add_transforms( + 'browser/browser/aboutCertError.ftl', + 'browser/browser/aboutCertError.ftl', + transforms_from( +""" +cert-error-details-cert-chain-label = { COPY(from_path, "certErrorDetailsCertChain.label") } +""", from_path="browser/chrome/browser/browser.properties")) diff --git a/toolkit/components/remotepagemanager/MessagePort.jsm b/toolkit/components/remotepagemanager/MessagePort.jsm index 4f0470e4a043..10d45db34f13 100644 --- a/toolkit/components/remotepagemanager/MessagePort.jsm +++ b/toolkit/components/remotepagemanager/MessagePort.jsm @@ -28,7 +28,13 @@ let RPMAccessManager = { "about:certerror": { "getFormatURLPref": ["app.support.baseURL"], "getBoolPref": ["security.certerrors.mitm.priming.enabled", - "security.enterprise_roots.auto-enabled"], + "security.enterprise_roots.auto-enabled", + "security.certerror.hideAddException", + "security.ssl.errorReporting.automatic", + "security.ssl.errorReporting.enabled"], + "getIntPref": ["services.settings.clock_skew_seconds", + "services.settings.last_update_seconds"], + "getAppBuildID": ["yes"], }, "about:privatebrowsing": { // "sendAsyncMessage": handled within AboutPrivateBrowsingHandler.jsm @@ -321,12 +327,12 @@ class MessagePort { return Services.prefs.getIntPref(aPref); } - getBoolPref(aPref) { + getBoolPref(aPref, defaultValue = false) { let principal = this.window.document.nodePrincipal; if (!RPMAccessManager.checkAllowAccess(principal, "getBoolPref", aPref)) { throw new Error("RPMAccessManager does not allow access to getBoolPref"); } - return Services.prefs.getBoolPref(aPref); + return Services.prefs.getBoolPref(aPref, defaultValue); } setBoolPref(aPref, aVal) {