Bumping manifests a=b2g-bump
[gecko.git] / b2g / components / ErrorPage.jsm
blobb967838fb9462c324935e8b90925c306619a2391
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 'use strict';
7 this.EXPORTED_SYMBOLS = ['ErrorPage'];
9 const Cu = Components.utils;
10 const Cc = Components.classes;
11 const Ci = Components.interfaces;
12 const kErrorPageFrameScript = 'chrome://b2g/content/ErrorPage.js';
14 Cu.import('resource://gre/modules/Services.jsm');
15 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
17 XPCOMUtils.defineLazyGetter(this, "CertOverrideService", function () {
18   return Cc["@mozilla.org/security/certoverride;1"]
19          .getService(Ci.nsICertOverrideService);
20 });
22 /**
23  * A class to add exceptions to override SSL certificate problems.
24  * The functionality itself is borrowed from exceptionDialog.js.
25  */
26 function SSLExceptions(aCallback, aUri, aWindow) {
27   this._finishCallback = aCallback;
28   this._uri = aUri;
29   this._window = aWindow;
32 SSLExceptions.prototype = {
33   _finishCallback: null,
34   _window: null,
35   _uri: null,
36   _temporary: null,
37   _sslStatus: null,
39   getInterface: function SSLE_getInterface(aIID) {
40     return this.QueryInterface(aIID);
41   },
43   QueryInterface: XPCOMUtils.generateQI([Ci.nsIBadCertListener2]),
45   /**
46    * To collect the SSL status we intercept the certificate error here
47    * and store the status for later use.
48    */
49   notifyCertProblem: function SSLE_notifyCertProblem(aSocketInfo,
50                                                      aSslStatus,
51                                                      aTargetHost) {
52     this._sslStatus = aSslStatus.QueryInterface(Ci.nsISSLStatus);
53     Services.tm.currentThread.dispatch({
54       run: this._addOverride.bind(this)
55     }, Ci.nsIThread.DISPATCH_NORMAL);
56     return true; // suppress error UI
57   },
59   /**
60    * Attempt to download the certificate for the location specified to get
61    * the SSLState for the certificate and the errors.
62    */
63   _checkCert: function SSLE_checkCert() {
64     this._sslStatus = null;
65     if (!this._uri) {
66       return;
67     }
68     let req = new this._window.XMLHttpRequest();
69     try {
70       req.open("GET", this._uri.prePath, true);
71       req.channel.notificationCallbacks = this;
72       let xhrHandler = (function() {
73         req.removeEventListener("load", xhrHandler);
74         req.removeEventListener("error", xhrHandler);
75         if (!this._sslStatus) {
76           // Got response from server without an SSL error.
77           if (this._finishCallback) {
78             this._finishCallback();
79           }
80         }
81       }).bind(this);
82       req.addEventListener("load", xhrHandler);
83       req.addEventListener("error", xhrHandler);
84       req.send(null);
85     } catch (e) {
86       // We *expect* exceptions if there are problems with the certificate
87       // presented by the site.  Log it, just in case, but we can proceed here,
88       // with appropriate sanity checks
89       Components.utils.reportError("Attempted to connect to a site with a bad certificate in the add exception dialog. " +
90                                    "This results in a (mostly harmless) exception being thrown. " +
91                                    "Logged for information purposes only: " + e);
92     }
93   },
95   /**
96    * Internal method to create an override.
97    */
98   _addOverride: function SSLE_addOverride() {
99     let SSLStatus = this._sslStatus;
100     let uri = this._uri;
101     let flags = 0;
103     if (SSLStatus.isUntrusted) {
104       flags |= Ci.nsICertOverrideService.ERROR_UNTRUSTED;
105     }
106     if (SSLStatus.isDomainMismatch) {
107       flags |= Ci.nsICertOverrideService.ERROR_MISMATCH;
108     }
109     if (SSLStatus.isNotValidAtThisTime) {
110       flags |= Ci.nsICertOverrideService.ERROR_TIME;
111     }
113     CertOverrideService.rememberValidityOverride(
114       uri.asciiHost,
115       uri.port,
116       SSLStatus.serverCert,
117       flags,
118       this._temporary);
120     if (this._finishCallback) {
121       this._finishCallback();
122     }
123   },
125   /**
126    * Creates a permanent exception to override all overridable errors for
127    * the given URL.
128    */
129   addException: function SSLE_addException(aTemporary) {
130     this._temporary = aTemporary;
131     this._checkCert();
132   }
135 let ErrorPage = {
136   _addCertException: function(aMessage) {
137     let frameLoaderOwner = aMessage.target.QueryInterface(Ci.nsIFrameLoaderOwner);
138     let win = frameLoaderOwner.ownerDocument.defaultView;
139     let mm = frameLoaderOwner.frameLoader.messageManager;
141     let uri = Services.io.newURI(aMessage.data.url, null, null);
142     let sslExceptions = new SSLExceptions((function() {
143       mm.sendAsyncMessage('ErrorPage:ReloadPage');
144     }).bind(this), uri, win);
145     try {
146       sslExceptions.addException(!aMessage.data.isPermanent);
147     } catch (e) {
148       dump("Failed to set cert exception: " + e + "\n");
149     }
150   },
152   _listenError: function(frameLoader) {
153     let self = this;
154     let frameElement = frameLoader.ownerElement;
155     let injectErrorPageScript = function() {
156       let mm = frameLoader.messageManager;
157       try {
158         mm.loadFrameScript(kErrorPageFrameScript, true, true);
159       } catch (e) {
160         dump('Error loading ' + kErrorPageFrameScript + ' as frame script: ' + e + '\n');
161       }
162       mm.addMessageListener('ErrorPage:AddCertException', self._addCertException.bind(self));
163       frameElement.removeEventListener('mozbrowsererror', injectErrorPageScript, true);
164     };
166     frameElement.addEventListener('mozbrowsererror',
167                                   injectErrorPageScript,
168                                   true // use capture
169                                  );
170   },
172   init: function errorPageInit() {
173     Services.obs.addObserver(this, 'inprocess-browser-shown', false);
174     Services.obs.addObserver(this, 'remote-browser-shown', false);
175   },
177   observe: function errorPageObserve(aSubject, aTopic, aData) {
178     let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
179     // Ignore notifications that aren't from a BrowserOrApp
180     if (!frameLoader.ownerIsBrowserOrAppFrame) {
181       return;
182     }
183     this._listenError(frameLoader);
184   }
187 ErrorPage.init();