Bug 469848: Add bad certificate exceptions without showing a separate UI [r=mark.finkle]
authorSteffen Imhof <steffen.imhof@googlemail.com>
Mon, 26 Oct 2009 15:16:35 -0400
changeset 65720 3f197bb3b5f2d1853b5dd304f90692321ef327c5
parent 65719 743aee66edc0e9891efa5f19a4d1e466dc8f7881
child 65721 84cc56c6c01d4db9e385794fc4d0c3757b513979
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmark
bugs469848
Bug 469848: Add bad certificate exceptions without showing a separate UI [r=mark.finkle]
mobile/chrome/content/browser.js
mobile/chrome/content/browser.xul
mobile/chrome/content/exceptions.js
mobile/chrome/jar.mn
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -833,35 +833,32 @@ var Browser = {
     var ot = aEvent.originalTarget;
     var errorDoc = ot.ownerDocument;
 
     // If the event came from an ssl error page, it is probably either the "Add
     // Exception…" or "Get me out of here!" button
     if (/^about:certerror\?e=nssBadCert/.test(errorDoc.documentURI)) {
       if (ot == errorDoc.getElementById("temporaryExceptionButton") ||
           ot == errorDoc.getElementById("permanentExceptionButton")) {
-        var params = { exceptionAdded : false };
-
         try {
-          switch (gPrefService.getIntPref("browser.ssl_override_behavior")) {
-            case 2 : // Pre-fetch & pre-populate
-              params.prefetchCert = true;
-            case 1 : // Pre-populate
-              params.location = errorDoc.location.href;
+          // add a new SSL exception for this URL
+          let uri = gIOService.newURI(errorDoc.location.href, null, null);
+          let sslExceptions = new SSLExceptions();
+
+          if (ot == errorDoc.getElementById("permanentExceptionButton")) {
+            sslExceptions.addPermanentException(uri);
+          } else {
+            sslExceptions.addTemporaryException(uri);
           }
         } catch (e) {
-          Components.utils.reportError("Couldn't get ssl_override pref: " + e);
+          dump("EXCEPTION handle content command: " + e + "\n" );
         }
 
-        window.openDialog('chrome://pippki/content/exceptionDialog.xul',
-                          '','chrome,centerscreen,modal', params);
-
-        // If the user added the exception cert, attempt to reload the page
-        if (params.exceptionAdded)
-          errorDoc.location.reload();
+        // automatically reload after the exception was added  
+        errorDoc.location.reload();
       }
       else if (ot == errorDoc.getElementById('getMeOutOfHereButton')) {
         // Get the start page from the *default* pref branch, not the user's
         var defaultPrefs = Cc["@mozilla.org/preferences-service;1"]
                           .getService(Ci.nsIPrefService).getDefaultBranch(null);
         var url = "about:blank";
         try {
           url = defaultPrefs.getCharPref("browser.startup.homepage");
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -66,16 +66,17 @@
 #endif
         onkeypress="onDebugKeyPress(event);"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml">
 
   <script type="application/x-javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="application/x-javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/commandUtil.js"/>
+  <script type="application/x-javascript" src="chrome://browser/content/exceptions.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/browser.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/browser-ui.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/sanitize.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/preferences.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/extensions.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/downloads.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/console.js"/>
   <script type="application/x-javascript" src="chrome://browser/content/Util.js"/>
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/content/exceptions.js
@@ -0,0 +1,160 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnathan Nightingale <johnath@mozilla.com>
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+ *   Steffen Imhof <steffen.imhof@googlemail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+
+/**
+  A class to add exceptions to override SSL certificate problems. The functionality
+  itself is borrowed from exceptionDialog.js.
+*/
+function SSLExceptions() {
+  this._overrideService = Cc["@mozilla.org/security/certoverride;1"]
+                          .getService(Ci.nsICertOverrideService);
+}
+
+
+SSLExceptions.prototype = {
+  _overrideService: null,
+  _sslStatus: null,
+
+  getInterface: function SSLE_getInterface(aIID) {
+    return this.QueryInterface(aIID);
+  },
+  QueryInterface: function SSLE_QueryInterface(aIID) {
+    if (aIID.equals(Ci.nsIBadCertListener2) ||
+        aIID.equals(Ci.nsISupports))
+      return this;
+
+    throw Components.results.NS_ERROR_NO_INTERFACE;
+  },
+
+  /**
+    To collect the SSL status we intercept the certificate error here
+    and store the status for later use.
+  */
+  notifyCertProblem: function SSLE_notifyCertProblem(socketInfo, sslStatus, targetHost) {
+    this._sslStatus = sslStatus.QueryInterface(Ci.nsISSLStatus);
+    return true; // suppress error UI
+  },
+
+  /**
+    Returns true if the private browsing mode is currently active
+   */
+  _inPrivateBrowsingMode: function SSLE_inPrivateBrowsingMode() {
+    try {
+      var pb = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
+      return pb.privateBrowsingEnabled;
+    } catch (ex) {
+      Components.utils.reportError("Could not get the Private Browsing service");
+    }
+    return false;
+  },
+
+  /**
+    Attempt to download the certificate for the location specified to get the SSLState
+    for the certificate and the errors.
+   */
+  _checkCert: function SSLE_checkCert(aURI) {
+    this._sslStatus = null;
+  
+    var req = new XMLHttpRequest();
+    try {
+      if(aURI) {
+        req.open("GET", aURI.prePath, false);
+        req.channel.notificationCallbacks = this;
+        req.send(null);
+      }
+    } catch (e) {
+      // We *expect* exceptions if there are problems with the certificate
+      // presented by the site.  Log it, just in case, but we can proceed here,
+      // with appropriate sanity checks
+      Components.utils.reportError("Attempted to connect to a site with a bad certificate in the add exception dialog. " +
+                                   "This results in a (mostly harmless) exception being thrown. " +
+                                   "Logged for information purposes only: " + e);
+    }
+
+    return this._sslStatus;
+  },
+
+  /**
+    Internal method to create an override.
+  */
+  _addOverride: function SSLE_addOverride(aURI, temporary) {
+    var SSLStatus = this._checkCert(aURI);
+    var certificate = SSLStatus.serverCert;
+
+    var flags = 0;
+
+    // in private browsing do not store exceptions permanently ever
+    if (this._inPrivateBrowsingMode()) {
+      temporary = true;
+    }
+
+    if(SSLStatus.isUntrusted)
+      flags |= this._overrideService.ERROR_UNTRUSTED;
+    if(SSLStatus.isDomainMismatch)
+      flags |= this._overrideService.ERROR_MISMATCH;
+    if(SSLStatus.isNotValidAtThisTime)
+      flags |= this._overrideService.ERROR_TIME;
+
+    this._overrideService.rememberValidityOverride(
+      aURI.asciiHost,
+      aURI.port,
+      certificate,
+      flags,
+      temporary);
+  },
+
+  /**
+    Creates a permanent exception to override all overridable errors for
+    the given URL.
+  */
+  addPermanentException: function SSLE_addPermanentException(aURI) {
+    this._addOverride(aURI, false);
+  },
+
+  /**
+    Creates a temporary exception to override all overridable errors for
+    the given URL.
+  */
+  addTemporaryException: function SSLE_addTemporaryException(aURI) {
+    this._addOverride(aURI, true);
+  }
+};
--- a/mobile/chrome/jar.mn
+++ b/mobile/chrome/jar.mn
@@ -28,16 +28,17 @@ chrome.jar:
 % content branding %content/branding/
 * content/sanitize.xul                 (content/sanitize.xul)
 * content/sanitize.js                  (content/sanitize.js)
 * content/BrowserView.js               (content/BrowserView.js)
   content/TileManager.js               (TileManager.js)
 * content/InputHandler.js              (content/InputHandler.js)
   content/Util.js                      (content/Util.js)
   content/preferences.js               (content/preferences.js)
+  content/exceptions.js                (content/exceptions.js)
   content/extensions.js                (content/extensions.js)
   content/downloads.js                 (content/downloads.js)
   content/console.js                   (content/console.js)
   content/prompt/alert.xul             (content/prompt/alert.xul)
   content/prompt/confirm.xul           (content/prompt/confirm.xul)
   content/prompt/prompt.xul            (content/prompt/prompt.xul)
   content/prompt/promptPassword.xul    (content/prompt/promptPassword.xul)
   content/prompt/select.xul            (content/prompt/select.xul)