michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let Cc = Components.classes; michael@0: let Ci = Components.interfaces; michael@0: let Cu = Components.utils; michael@0: michael@0: Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); michael@0: michael@0: /** michael@0: A class to add exceptions to override SSL certificate problems. The functionality michael@0: itself is borrowed from exceptionDialog.js. michael@0: */ michael@0: function SSLExceptions() { michael@0: this._overrideService = Cc["@mozilla.org/security/certoverride;1"] michael@0: .getService(Ci.nsICertOverrideService); michael@0: } michael@0: michael@0: michael@0: SSLExceptions.prototype = { michael@0: _overrideService: null, michael@0: _sslStatus: null, michael@0: michael@0: getInterface: function SSLE_getInterface(aIID) { michael@0: return this.QueryInterface(aIID); michael@0: }, michael@0: QueryInterface: function SSLE_QueryInterface(aIID) { michael@0: if (aIID.equals(Ci.nsIBadCertListener2) || michael@0: aIID.equals(Ci.nsISupports)) michael@0: return this; michael@0: michael@0: throw Components.results.NS_ERROR_NO_INTERFACE; michael@0: }, michael@0: michael@0: /** michael@0: To collect the SSL status we intercept the certificate error here michael@0: and store the status for later use. michael@0: */ michael@0: notifyCertProblem: function SSLE_notifyCertProblem(socketInfo, sslStatus, targetHost) { michael@0: this._sslStatus = sslStatus.QueryInterface(Ci.nsISSLStatus); michael@0: return true; // suppress error UI michael@0: }, michael@0: michael@0: /** michael@0: Attempt to download the certificate for the location specified to get the SSLState michael@0: for the certificate and the errors. michael@0: */ michael@0: _checkCert: function SSLE_checkCert(aURI) { michael@0: this._sslStatus = null; michael@0: michael@0: var req = new XMLHttpRequest(); michael@0: try { michael@0: if(aURI) { michael@0: req.open("GET", aURI.prePath, false); michael@0: req.channel.notificationCallbacks = this; michael@0: req.send(null); michael@0: } michael@0: } catch (e) { michael@0: // We *expect* exceptions if there are problems with the certificate michael@0: // presented by the site. Log it, just in case, but we can proceed here, michael@0: // with appropriate sanity checks michael@0: Components.utils.reportError("Attempted to connect to a site with a bad certificate in the add exception dialog. " + michael@0: "This results in a (mostly harmless) exception being thrown. " + michael@0: "Logged for information purposes only: " + e); michael@0: } michael@0: michael@0: return this._sslStatus; michael@0: }, michael@0: michael@0: /** michael@0: Internal method to create an override. michael@0: */ michael@0: _addOverride: function SSLE_addOverride(aURI, aWindow, temporary) { michael@0: var SSLStatus = this._checkCert(aURI); michael@0: var certificate = SSLStatus.serverCert; michael@0: michael@0: var flags = 0; michael@0: michael@0: // in private browsing do not store exceptions permanently ever michael@0: if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) { michael@0: temporary = true; michael@0: } michael@0: michael@0: if(SSLStatus.isUntrusted) michael@0: flags |= this._overrideService.ERROR_UNTRUSTED; michael@0: if(SSLStatus.isDomainMismatch) michael@0: flags |= this._overrideService.ERROR_MISMATCH; michael@0: if(SSLStatus.isNotValidAtThisTime) michael@0: flags |= this._overrideService.ERROR_TIME; michael@0: michael@0: this._overrideService.rememberValidityOverride( michael@0: aURI.asciiHost, michael@0: aURI.port, michael@0: certificate, michael@0: flags, michael@0: temporary); michael@0: }, michael@0: michael@0: /** michael@0: Creates a permanent exception to override all overridable errors for michael@0: the given URL. michael@0: */ michael@0: addPermanentException: function SSLE_addPermanentException(aURI, aWindow) { michael@0: this._addOverride(aURI, aWindow, false); michael@0: }, michael@0: michael@0: /** michael@0: Creates a temporary exception to override all overridable errors for michael@0: the given URL. michael@0: */ michael@0: addTemporaryException: function SSLE_addTemporaryException(aURI, aWindow) { michael@0: this._addOverride(aURI, aWindow, true); michael@0: } michael@0: };