Bug 1591749 - Enhance SeaMonkey's certificate / net error code. r=frg
authorIan Neal <iann_cvs@blueyonder.co.uk>
Tue, 19 Nov 2019 11:46:55 +0100
changeset 37560 54cb02ce13e7e6ab73b7c2b4ee47c024e9a1dc3c
parent 37559 a0fa0fb92d758844b51241250b4881cfefeb5451
child 37561 64188fcfd0e255b5b0d4eb6735fd00e86a798186
push id396
push userclokep@gmail.com
push dateMon, 06 Jan 2020 23:11:57 +0000
reviewersfrg
bugs1591749
Bug 1591749 - Enhance SeaMonkey's certificate / net error code. r=frg
suite/base/content/certError.js
suite/base/content/certError.xhtml
suite/base/jar.mn
suite/locales/en-US/chrome/common/certError.dtd
suite/themes/classic/communicator/certError.css
suite/themes/modern/communicator/certError.css
--- a/suite/base/content/certError.js
+++ b/suite/base/content/certError.js
@@ -22,35 +22,66 @@ document.getElementById("technicalConten
 document.getElementById("expertContentHeading")
         .addEventListener("click", function() { toggle("expertContent"); });
 
 let gSearchParams;
 
 // Set to true on init if the error code is nssBadCert.
 let gIsCertError;
 
+// Set to true on init if a neterror.
+let gIsNetError;
+
 initPage();
 
 function getErrorCode() {
   return gSearchParams.get("e");
 }
 
 function getCSSClass() {
   return gSearchParams.get("s");
 }
 
 function getDescription() {
   return gSearchParams.get("d");
 }
 
+function retryThis(buttonEl) {
+  // Note: The application may wish to handle switching off "offline mode"
+  // before this event handler runs, but using a capturing event handler.
+
+  // Session history has the URL of the page that failed
+  // to load, not the one of the error page. So, just call
+  // reload(), which will also repost POST data correctly.
+  try {
+    location.reload();
+  } catch (e) {
+    // We probably tried to reload a URI that caused an exception to
+    // occur;  e.g. a nonexistent file.
+  }
+
+  buttonEl.disabled = true;
+}
+
 function initPage() {
   gSearchParams = new URLSearchParams(document.documentURI.split("?")[1]);
 
   let err = getErrorCode();
+  // List of neterror pages which have no error code and
+  // could have an illustration instead.
+  let illustratedErrors = [
+    "malformedURI", "dnsNotFound", "connectionFailure", "netInterrupt",
+    "netTimeout", "netReset", "netOffline",
+  ];
+  if (illustratedErrors.includes(err)) {
+    document.body.classList.add("illustrated", err);
+  }
+
   gIsCertError = (err == "nssBadCert");
+  gIsNetError = (document.documentURI.startsWith("about:neterror"));
 
   let pageTitle = document.getElementById("ept_" + err);
   if (pageTitle) {
     document.title = pageTitle.textContent;
   }
 
   // If it's an unknown error or there's no title or description defined,
   // get the generic message.
@@ -65,58 +96,112 @@ function initPage() {
   if (title) {
     title.innerHTML = errTitle.innerHTML;
   }
 
   let sd = document.getElementById("errorShortDescText");
   if (sd) {
     if (gIsCertError) {
       sd.innerHTML = errDesc.innerHTML;
+    } else if (!err || err == "unknownProtocolFound") {
+      sd.remove();
     } else {
-      sd.textContent = getDescription();
+      let desc = getDescription();
+      if (!illustratedErrors.includes(err) && gIsNetError) {
+        let codeRe = /<a id="errorCode" title="([^"]+)">/;
+        let codeResult = codeRe.exec(desc);
+        if (codeResult) {
+          let msg = desc.slice(0, codeResult.index) + codeResult[1];
+          sd.textContent = msg;
+          sd.className = "wrap";
+        } else {
+          sd.textContent = desc;
+        }
+      } else {
+        sd.textContent = desc;
+      }
     }
   }
 
   let xd = document.getElementById("errorShortDescExtra");
   if (xd) {
     let errExtra = document.getElementById("ex_" + err);
     if (gIsCertError && errExtra) {
       xd.innerHTML = errExtra.innerHTML;
     } else {
       xd.remove();
     }
   }
 
+  let ld = document.getElementById("errorLongDesc");
+  if (ld && !gIsCertError) {
+    ld.innerHTML = errDesc.innerHTML;
+  }
+
   // Remove undisplayed errors to avoid bug 39098.
   let errContainer = document.getElementById("errorContainer");
   errContainer.remove();
 
-  if (gIsCertError) {
+  if (gIsCertError || err == "inadequateSecurityError") {
     for (let host of document.querySelectorAll(".hostname")) {
       host.textContent = location.host;
     }
   }
 
+  if (gIsCertError || err == "sslv3Used") {
+    document.body.classList.add("certerror");
+  }
+
+  if (gIsCertError || err == "remoteXUL" || err == "cspBlocked" ||
+      err == "inadequateSecurityError") {
+    // Remove the "Try again" button for certificate errors, remote XUL errors,
+    // CSP violations (Bug 553180) and HTTP/2 inadequate security,
+    // given that it is useless.
+    document.getElementById("netErrorButtonContainer").style.display = "none";
+  }
+
   let className = getCSSClass();
+  if (className && className != "expertBadCert") {
+    // Associate a CSS class with the root of the page, if one was passed in,
+    // to allow custom styling.
+    // Not "expertBadCert" though, don't want to deal with the favicon
+    document.documentElement.classList.add(className);
+  }
+
   if (className == "expertBadCert") {
     toggle("technicalContent");
     toggle("expertContent");
   }
 
   // Disallow overrides if this is a Strict-Transport-Security
   // host and the cert is bad (STS Spec section 7.3);
   // or if the cert error is in a frame (bug 633691).
-  if (className == "badStsCert" || window != top) {
-    document.getElementById("expertContent").setAttribute("hidden", "true");
+  if (className == "badStsCert" || window != top || !gIsCertError) {
+    let expertContent = document.getElementById("expertContent");
+    expertContent.remove();
   }
   if (className == "badStsCert") {
     document.getElementById("badStsCertExplanation").removeAttribute("hidden");
   }
 
-  addDomainErrorLinks();
+  // For neterrors set a suitable class.
+  if (gIsNetError) {
+    document.body.classList.add("neterror");
+  }
+
+  // For neterrors and null error codes do not show the What Should I Do and
+  // Technical Details sections.
+  if (gIsNetError || !err) {
+    let whatShould = document.getElementById("whatShouldIDoContent");
+    whatShould.remove();
+    let technicalContent = document.getElementById("technicalContent");
+    technicalContent.remove();
+  } else {
+    addDomainErrorLinks();
+  }
 }
 
 /* In the case of SSL error pages about domain mismatch, see if
    we can hyperlink the user to the correct site.  We don't want
    to do this generically since it allows MitM attacks to redirect
    users to a site under attacker control, but in certain cases
    it is safe (and helpful!) to do so.  Bug 402210
 */
@@ -137,18 +222,18 @@ function addDomainErrorLinks() {
   var domainRe = /<a id="cert_domain_link" title="([^"]+)">/;
   var domainResult = domainRe.exec(desc);
   // The order of these links in the description is fixed in
   // TransportSecurityInfo.cpp:formatOverridableCertErrorMessage.
   var firstResult = domainResult;
   if (!domainResult)
     firstResult = codeResult;
   if (!firstResult) {
-      sd.textContent = desc;
-      return;
+    sd.textContent = desc;
+    return;
   }
 
   // Remove sd's existing children.
   sd.textContent = "";
 
   // Everything up to the link should be text content.
   sd.appendChild(document.createTextNode(desc.slice(0, firstResult.index)));
 
--- a/suite/base/content/certError.xhtml
+++ b/suite/base/content/certError.xhtml
@@ -29,25 +29,73 @@
   </head>
 
   <body dir="&locale.dir;">
 
     <!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
     <div id="errorContainer" style="display: none;">
       <div id="errorPageTitlesContainer">
         <span id="ept_nssBadCert">&certerror.pagetitle;</span>
+        <span id="ept_dnsNotFound">&dnsNotFound.pageTitle;</span>
+        <span id="ept_malformedURI">&malformedURI.pageTitle;</span>
       </div>
       <div id="errorTitlesContainer">
         <h1 id="et_generic">&generic.title;</h1>
+        <h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
+        <h1 id="et_fileNotFound">&fileNotFound.title;</h1>
+        <h1 id="et_fileAccessDenied">&fileAccessDenied.title;</h1>
+        <h1 id="et_malformedURI">&malformedURI.title;</h1>
+        <h1 id="et_unknownProtocolFound">&unknownProtocolFound.title;</h1>
+        <h1 id="et_connectionFailure">&connectionFailure.title;</h1>
+        <h1 id="et_netTimeout">&netTimeout.title;</h1>
+        <h1 id="et_redirectLoop">&redirectLoop.title;</h1>
+        <h1 id="et_unknownSocketType">&unknownSocketType.title;</h1>
+        <h1 id="et_netReset">&netReset.title;</h1>
+        <h1 id="et_notCached">&notCached.title;</h1>
+        <h1 id="et_netOffline">&netOffline.title;</h1>
+        <h1 id="et_netInterrupt">&netInterrupt.title;</h1>
+        <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
+        <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1>
+        <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1>
+        <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1>
+        <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1>
+        <h1 id="et_nssFailure2">&nssFailure2.title;</h1>
         <h1 id="et_nssBadCert">&certerror.longpagetitle;</h1>
+        <h1 id="et_cspBlocked">&cspBlocked.title;</h1>
+        <h1 id="et_remoteXUL">&remoteXUL.title;</h1>
+        <h1 id="et_corruptedContentErrorv2">&corruptedContentErrorv2.title;</h1>
+        <h1 id="et_inadequateSecurityError">&inadequateSecurityError.title;</h1>
       </div>
       <div id="errorDescriptionsContainer">
         <div id="ed_generic">&generic.longDesc;</div>
+        <div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
+        <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
+        <div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
+        <div id="ed_malformedURI">&malformedURI.longDesc;</div>
+        <div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
+        <div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
+        <div id="ed_netTimeout">&netTimeout.longDesc;</div>
+        <div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
+        <div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
+        <div id="ed_netReset">&netReset.longDesc;</div>
+        <div id="ed_notCached">&notCached.longDesc;</div>
+        <div id="ed_netOffline">&netOffline.longDesc2;</div>
+        <div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
+        <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
+        <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div>
+        <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
+        <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
+        <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
+        <div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
         <div id="ed_nssBadCert">&certerror.introPara1a;</div>
         <div id="ex_nssBadCert">&certerror.introPara2;</div>
+        <div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
+        <div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
+        <div id="ed_corruptedContentErrorv2">&corruptedContentErrorv2.longDesc;</div>
+        <div id="ed_inadequateSecurityError">&inadequateSecurityError.longDesc;</div>
       </div>
     </div>
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
 
       <!-- Error Title -->
       <div id="errorTitle">
@@ -58,16 +106,19 @@
       <div id="errorLongContent">
 
         <!-- Short Description -->
         <div id="errorShortDesc">
           <p id="errorShortDescText"/>
           <p id="errorShortDescExtra"/>
         </div>
 
+        <!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
+        <div id="errorLongDesc"/>
+
         <div id="whatShouldIDoContent">
           <h2>&certerror.whatShouldIDo.heading;</h2>
           <div id="whatShouldIDoContentText">
             <p>&certerror.whatShouldIDo.content;</p>
             <p id="badStsCertExplanation"
                hidden="true">&certerror.whatShouldIDo.badStsCertExplanation;</p>
             <span id="getMeOutOfHereButton"
                   class="button"
@@ -87,16 +138,23 @@
           <div>
             <p>&certerror.expert.content;</p>
             <p>&certerror.expert.contentPara2;</p>
             <span id="exceptionDialogButton"
                   class="button"
                   label="&certerror.addException.label;"/>
           </div>
         </div>
+
+        <div id="netErrorButtonContainer" class="button-container">
+          <button id="errorTryAgain"
+                  class="primary"
+                  autocomplete="off"
+                  onclick="retryThis(this);">&retry.label;</button>
+        </div>
       </div>
     </div>
 
     <!--
     - Note: It is important to run the script this way, instead of using
     - a window.onload function. This is because error pages are loaded as
     - LOAD_BACKGROUND, which means that onload handlers will not be executed.
     -->
--- a/suite/base/jar.mn
+++ b/suite/base/jar.mn
@@ -2,16 +2,17 @@
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.comm.jar:
 
 comm.jar:
 % content communicator %content/communicator/ contentaccessible=yes
 % override chrome://global/content/license.html chrome://communicator/content/license.html
+% override chrome://global/content/netError.xhtml chrome://communicator/content/certError.xhtml
 % overlay chrome://global/content/viewSource.xul chrome://communicator/content/viewSourceOverlay.xul
 % overlay chrome://global/content/viewPartialSource.xul chrome://communicator/content/viewSourceOverlay.xul
 % overlay chrome://editor/content/EdAdvancedEdit.xul chrome://communicator/content/helpEditorOverlay.xul
 % overlay chrome://editor/content/EdImageProps.xul chrome://communicator/content/helpEditorOverlay.xul
 % overlay chrome://editor/content/EditorPublish.xul chrome://communicator/content/helpEditorOverlay.xul
 % overlay chrome://editor/content/EditorPublishProgress.xul chrome://communicator/content/helpEditorOverlay.xul
 % overlay chrome://editor/content/EditorPublishSettings.xul chrome://communicator/content/helpEditorOverlay.xul
 % overlay chrome://editor/content/EdLinkProps.xul chrome://communicator/content/helpEditorOverlay.xul
--- a/suite/locales/en-US/chrome/common/certError.dtd
+++ b/suite/locales/en-US/chrome/common/certError.dtd
@@ -34,8 +34,11 @@ certificate.">
 can tell &brandShortName; to start trusting this website's identification.
 <b>Even if you trust the website, this error could mean that someone is
 tampering with your connection.</b>">
 <!ENTITY certerror.expert.contentPara2 "Don't add an exception unless
 you know there's a good reason why this website doesn't use trusted identification.">
 <!ENTITY certerror.addException.label "Add Exception…">
 
 <!ENTITY certerror.technical.heading "Technical Details">
+
+<!ENTITY dnsNotFound.pageTitle "Server Not Found">
+<!ENTITY malformedURI.pageTitle "Invalid URL">
--- a/suite/themes/classic/communicator/certError.css
+++ b/suite/themes/classic/communicator/certError.css
@@ -48,16 +48,20 @@ body[dir="rtl"] #errorPageContainer {
 #errorTitle {
   margin-inline-start: 80px;
 }
 
 #errorLongContent {
   margin-inline-start: 80px;
 }
 
+#errorShortDescText.wrap {
+  white-space: pre-wrap;
+}
+
 #technicalContent > h2, #expertContent > h2 {
   cursor: pointer;
   padding-inline-start: 20px;
   position: relative;
   left: -20px;
   background: url("chrome://messenger/skin/icons/twisty-open.png") left center no-repeat;
 }
 
--- a/suite/themes/modern/communicator/certError.css
+++ b/suite/themes/modern/communicator/certError.css
@@ -48,16 +48,20 @@ body[dir="rtl"] #errorPageContainer {
 #errorTitle {
   margin-inline-start: 80px;
 }
 
 #errorLongContent {
   margin-inline-start: 80px;
 }
 
+#errorShortDescText.wrap {
+  white-space: pre-wrap;
+}
+
 #technicalContent > h2, #expertContent > h2 {
   cursor: pointer;
   padding-inline-start: 20px;
   position: relative;
   left: -20px;
   background: url("chrome://global/skin/tree/twisty-open.gif") left center no-repeat;
 }