security/manager/pki/resources/content/exceptionDialog.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5
michael@0 6 var gDialog;
michael@0 7 var gBundleBrand;
michael@0 8 var gPKIBundle;
michael@0 9 var gSSLStatus;
michael@0 10 var gCert;
michael@0 11 var gChecking;
michael@0 12 var gBroken;
michael@0 13 var gNeedReset;
michael@0 14 var gSecHistogram;
michael@0 15 var gNsISecTel;
michael@0 16
michael@0 17 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
michael@0 18
michael@0 19 function badCertListener() {}
michael@0 20 badCertListener.prototype = {
michael@0 21 getInterface: function (aIID) {
michael@0 22 return this.QueryInterface(aIID);
michael@0 23 },
michael@0 24 QueryInterface: function(aIID) {
michael@0 25 if (aIID.equals(Components.interfaces.nsIBadCertListener2) ||
michael@0 26 aIID.equals(Components.interfaces.nsIInterfaceRequestor) ||
michael@0 27 aIID.equals(Components.interfaces.nsISupports))
michael@0 28 return this;
michael@0 29
michael@0 30 throw Components.results.NS_ERROR_NO_INTERFACE;
michael@0 31 },
michael@0 32 handle_test_result: function () {
michael@0 33 if (gSSLStatus)
michael@0 34 gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
michael@0 35 },
michael@0 36 notifyCertProblem: function MSR_notifyCertProblem(socketInfo, sslStatus, targetHost) {
michael@0 37 gBroken = true;
michael@0 38 gSSLStatus = sslStatus;
michael@0 39 this.handle_test_result();
michael@0 40 return true; // suppress error UI
michael@0 41 }
michael@0 42 }
michael@0 43
michael@0 44 function initExceptionDialog() {
michael@0 45 gNeedReset = false;
michael@0 46 gDialog = document.documentElement;
michael@0 47 gBundleBrand = document.getElementById("brand_bundle");
michael@0 48 gPKIBundle = document.getElementById("pippki_bundle");
michael@0 49 gSecHistogram = Components.classes["@mozilla.org/base/telemetry;1"].
michael@0 50 getService(Components.interfaces.nsITelemetry).
michael@0 51 getHistogramById("SECURITY_UI");
michael@0 52 gNsISecTel = Components.interfaces.nsISecurityUITelemetry;
michael@0 53
michael@0 54 var brandName = gBundleBrand.getString("brandShortName");
michael@0 55 setText("warningText", gPKIBundle.getFormattedString("addExceptionBrandedWarning2", [brandName]));
michael@0 56 gDialog.getButton("extra1").disabled = true;
michael@0 57
michael@0 58 var args = window.arguments;
michael@0 59 if (args && args[0]) {
michael@0 60 if (args[0].location) {
michael@0 61 // We were pre-seeded with a location.
michael@0 62 document.getElementById("locationTextBox").value = args[0].location;
michael@0 63 document.getElementById('checkCertButton').disabled = false;
michael@0 64
michael@0 65 // We can optionally pre-fetch the certificate too. Don't do this
michael@0 66 // synchronously, since it would prevent the window from appearing
michael@0 67 // until the fetch is completed, which could be multiple seconds.
michael@0 68 // Instead, let's use a timer to spawn the actual fetch, but update
michael@0 69 // the dialog to "checking..." state right away, so that the UI
michael@0 70 // is appropriately responsive. Bug 453855
michael@0 71 if (args[0].prefetchCert) {
michael@0 72
michael@0 73 document.getElementById("checkCertButton").disabled = true;
michael@0 74 gChecking = true;
michael@0 75 updateCertStatus();
michael@0 76
michael@0 77 window.setTimeout(checkCert, 0);
michael@0 78 }
michael@0 79 }
michael@0 80
michael@0 81 // Set out parameter to false by default
michael@0 82 args[0].exceptionAdded = false;
michael@0 83 }
michael@0 84 }
michael@0 85
michael@0 86 // returns true if found and global status could be set
michael@0 87 function findRecentBadCert(uri) {
michael@0 88 try {
michael@0 89 var certDB = Components.classes["@mozilla.org/security/x509certdb;1"]
michael@0 90 .getService(Components.interfaces.nsIX509CertDB);
michael@0 91 if (!certDB)
michael@0 92 return false;
michael@0 93 var recentCertsSvc = certDB.getRecentBadCerts(inPrivateBrowsingMode());
michael@0 94 if (!recentCertsSvc)
michael@0 95 return false;
michael@0 96
michael@0 97 var hostWithPort = uri.host + ":" + uri.port;
michael@0 98 gSSLStatus = recentCertsSvc.getRecentBadCert(hostWithPort);
michael@0 99 if (!gSSLStatus)
michael@0 100 return false;
michael@0 101
michael@0 102 gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
michael@0 103 if (!gCert)
michael@0 104 return false;
michael@0 105
michael@0 106 gBroken = true;
michael@0 107 }
michael@0 108 catch (e) {
michael@0 109 return false;
michael@0 110 }
michael@0 111 updateCertStatus();
michael@0 112 return true;
michael@0 113 }
michael@0 114
michael@0 115 /**
michael@0 116 * Attempt to download the certificate for the location specified, and populate
michael@0 117 * the Certificate Status section with the result.
michael@0 118 */
michael@0 119 function checkCert() {
michael@0 120
michael@0 121 gCert = null;
michael@0 122 gSSLStatus = null;
michael@0 123 gChecking = true;
michael@0 124 gBroken = false;
michael@0 125 updateCertStatus();
michael@0 126
michael@0 127 var uri = getURI();
michael@0 128
michael@0 129 // Is the cert already known in the list of recently seen bad certs?
michael@0 130 if (findRecentBadCert(uri) == true)
michael@0 131 return;
michael@0 132
michael@0 133 var req = new XMLHttpRequest();
michael@0 134 try {
michael@0 135 if(uri) {
michael@0 136 req.open('GET', uri.prePath, false);
michael@0 137 req.channel.notificationCallbacks = new badCertListener();
michael@0 138 req.send(null);
michael@0 139 }
michael@0 140 } catch (e) {
michael@0 141 // We *expect* exceptions if there are problems with the certificate
michael@0 142 // presented by the site. Log it, just in case, but we can proceed here,
michael@0 143 // with appropriate sanity checks
michael@0 144 Components.utils.reportError("Attempted to connect to a site with a bad certificate in the add exception dialog. " +
michael@0 145 "This results in a (mostly harmless) exception being thrown. " +
michael@0 146 "Logged for information purposes only: " + e);
michael@0 147 } finally {
michael@0 148 gChecking = false;
michael@0 149 }
michael@0 150
michael@0 151 if(req.channel && req.channel.securityInfo) {
michael@0 152 const Ci = Components.interfaces;
michael@0 153 gSSLStatus = req.channel.securityInfo
michael@0 154 .QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
michael@0 155 gCert = gSSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
michael@0 156 }
michael@0 157 updateCertStatus();
michael@0 158 }
michael@0 159
michael@0 160 /**
michael@0 161 * Build and return a URI, based on the information supplied in the
michael@0 162 * Certificate Location fields
michael@0 163 */
michael@0 164 function getURI() {
michael@0 165 // Use fixup service instead of just ioservice's newURI since it's quite likely
michael@0 166 // that the host will be supplied without a protocol prefix, resulting in malformed
michael@0 167 // uri exceptions being thrown.
michael@0 168 var fus = Components.classes["@mozilla.org/docshell/urifixup;1"]
michael@0 169 .getService(Components.interfaces.nsIURIFixup);
michael@0 170 var uri = fus.createFixupURI(document.getElementById("locationTextBox").value, 0);
michael@0 171
michael@0 172 if(!uri)
michael@0 173 return null;
michael@0 174
michael@0 175 if(uri.scheme == "http")
michael@0 176 uri.scheme = "https";
michael@0 177
michael@0 178 if (uri.port == -1)
michael@0 179 uri.port = 443;
michael@0 180
michael@0 181 return uri;
michael@0 182 }
michael@0 183
michael@0 184 function resetDialog() {
michael@0 185 document.getElementById("viewCertButton").disabled = true;
michael@0 186 document.getElementById("permanent").disabled = true;
michael@0 187 gDialog.getButton("extra1").disabled = true;
michael@0 188 setText("headerDescription", "");
michael@0 189 setText("statusDescription", "");
michael@0 190 setText("statusLongDescription", "");
michael@0 191 setText("status2Description", "");
michael@0 192 setText("status2LongDescription", "");
michael@0 193 setText("status3Description", "");
michael@0 194 setText("status3LongDescription", "");
michael@0 195 }
michael@0 196
michael@0 197 /**
michael@0 198 * Called by input textboxes to manage UI state
michael@0 199 */
michael@0 200 function handleTextChange() {
michael@0 201 var checkCertButton = document.getElementById('checkCertButton');
michael@0 202 checkCertButton.disabled = !(document.getElementById("locationTextBox").value);
michael@0 203 if (gNeedReset) {
michael@0 204 gNeedReset = false;
michael@0 205 resetDialog();
michael@0 206 }
michael@0 207 }
michael@0 208
michael@0 209 function updateCertStatus() {
michael@0 210 var shortDesc, longDesc;
michael@0 211 var shortDesc2, longDesc2;
michael@0 212 var shortDesc3, longDesc3;
michael@0 213 var use2 = false;
michael@0 214 var use3 = false;
michael@0 215 let bucketId = gNsISecTel.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_BASE;
michael@0 216 if(gCert) {
michael@0 217 if(gBroken) {
michael@0 218 var mms = "addExceptionDomainMismatchShort";
michael@0 219 var mml = "addExceptionDomainMismatchLong";
michael@0 220 var exs = "addExceptionExpiredShort";
michael@0 221 var exl = "addExceptionExpiredLong";
michael@0 222 var uts = "addExceptionUnverifiedOrBadSignatureShort";
michael@0 223 var utl = "addExceptionUnverifiedOrBadSignatureLong";
michael@0 224 var use1 = false;
michael@0 225 if (gSSLStatus.isDomainMismatch) {
michael@0 226 bucketId += gNsISecTel.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_DOMAIN;
michael@0 227 use1 = true;
michael@0 228 shortDesc = mms;
michael@0 229 longDesc = mml;
michael@0 230 }
michael@0 231 if (gSSLStatus.isNotValidAtThisTime) {
michael@0 232 bucketId += gNsISecTel.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_TIME;
michael@0 233 if (!use1) {
michael@0 234 use1 = true;
michael@0 235 shortDesc = exs;
michael@0 236 longDesc = exl;
michael@0 237 }
michael@0 238 else {
michael@0 239 use2 = true;
michael@0 240 shortDesc2 = exs;
michael@0 241 longDesc2 = exl;
michael@0 242 }
michael@0 243 }
michael@0 244 if (gSSLStatus.isUntrusted) {
michael@0 245 bucketId += gNsISecTel.WARNING_BAD_CERT_TOP_ADD_EXCEPTION_FLAG_UNTRUSTED;
michael@0 246 if (!use1) {
michael@0 247 use1 = true;
michael@0 248 shortDesc = uts;
michael@0 249 longDesc = utl;
michael@0 250 }
michael@0 251 else if (!use2) {
michael@0 252 use2 = true;
michael@0 253 shortDesc2 = uts;
michael@0 254 longDesc2 = utl;
michael@0 255 }
michael@0 256 else {
michael@0 257 use3 = true;
michael@0 258 shortDesc3 = uts;
michael@0 259 longDesc3 = utl;
michael@0 260 }
michael@0 261 }
michael@0 262 gSecHistogram.add(bucketId);
michael@0 263
michael@0 264 // In these cases, we do want to enable the "Add Exception" button
michael@0 265 gDialog.getButton("extra1").disabled = false;
michael@0 266
michael@0 267 // If the Private Browsing service is available and the mode is active,
michael@0 268 // don't store permanent exceptions, since they would persist after
michael@0 269 // private browsing mode was disabled.
michael@0 270 var inPrivateBrowsing = inPrivateBrowsingMode();
michael@0 271 var pe = document.getElementById("permanent");
michael@0 272 pe.disabled = inPrivateBrowsing;
michael@0 273 pe.checked = !inPrivateBrowsing;
michael@0 274
michael@0 275 setText("headerDescription", gPKIBundle.getString("addExceptionInvalidHeader"));
michael@0 276 }
michael@0 277 else {
michael@0 278 shortDesc = "addExceptionValidShort";
michael@0 279 longDesc = "addExceptionValidLong";
michael@0 280 gDialog.getButton("extra1").disabled = true;
michael@0 281 document.getElementById("permanent").disabled = true;
michael@0 282 }
michael@0 283
michael@0 284 // We're done checking the certificate, so allow the user to check it again.
michael@0 285 document.getElementById("checkCertButton").disabled = false;
michael@0 286 document.getElementById("viewCertButton").disabled = false;
michael@0 287
michael@0 288 // Notify observers about the availability of the certificate
michael@0 289 Components.classes["@mozilla.org/observer-service;1"]
michael@0 290 .getService(Components.interfaces.nsIObserverService)
michael@0 291 .notifyObservers(null, "cert-exception-ui-ready", null);
michael@0 292 }
michael@0 293 else if (gChecking) {
michael@0 294 shortDesc = "addExceptionCheckingShort";
michael@0 295 longDesc = "addExceptionCheckingLong";
michael@0 296 // We're checking the certificate, so we disable the Get Certificate
michael@0 297 // button to make sure that the user can't interrupt the process and
michael@0 298 // trigger another certificate fetch.
michael@0 299 document.getElementById("checkCertButton").disabled = true;
michael@0 300 document.getElementById("viewCertButton").disabled = true;
michael@0 301 gDialog.getButton("extra1").disabled = true;
michael@0 302 document.getElementById("permanent").disabled = true;
michael@0 303 }
michael@0 304 else {
michael@0 305 shortDesc = "addExceptionNoCertShort";
michael@0 306 longDesc = "addExceptionNoCertLong";
michael@0 307 // We're done checking the certificate, so allow the user to check it again.
michael@0 308 document.getElementById("checkCertButton").disabled = false;
michael@0 309 document.getElementById("viewCertButton").disabled = true;
michael@0 310 gDialog.getButton("extra1").disabled = true;
michael@0 311 document.getElementById("permanent").disabled = true;
michael@0 312 }
michael@0 313
michael@0 314 setText("statusDescription", gPKIBundle.getString(shortDesc));
michael@0 315 setText("statusLongDescription", gPKIBundle.getString(longDesc));
michael@0 316
michael@0 317 if (use2) {
michael@0 318 setText("status2Description", gPKIBundle.getString(shortDesc2));
michael@0 319 setText("status2LongDescription", gPKIBundle.getString(longDesc2));
michael@0 320 }
michael@0 321
michael@0 322 if (use3) {
michael@0 323 setText("status3Description", gPKIBundle.getString(shortDesc3));
michael@0 324 setText("status3LongDescription", gPKIBundle.getString(longDesc3));
michael@0 325 }
michael@0 326
michael@0 327 gNeedReset = true;
michael@0 328 }
michael@0 329
michael@0 330 /**
michael@0 331 * Handle user request to display certificate details
michael@0 332 */
michael@0 333 function viewCertButtonClick() {
michael@0 334 gSecHistogram.add(gNsISecTel.WARNING_BAD_CERT_TOP_CLICK_VIEW_CERT);
michael@0 335 if (gCert)
michael@0 336 viewCertHelper(this, gCert);
michael@0 337
michael@0 338 }
michael@0 339
michael@0 340 /**
michael@0 341 * Handle user request to add an exception for the specified cert
michael@0 342 */
michael@0 343 function addException() {
michael@0 344 if(!gCert || !gSSLStatus)
michael@0 345 return;
michael@0 346
michael@0 347 var overrideService = Components.classes["@mozilla.org/security/certoverride;1"]
michael@0 348 .getService(Components.interfaces.nsICertOverrideService);
michael@0 349 var flags = 0;
michael@0 350 let confirmBucketId = gNsISecTel.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_BASE;
michael@0 351 if (gSSLStatus.isUntrusted) {
michael@0 352 flags |= overrideService.ERROR_UNTRUSTED;
michael@0 353 confirmBucketId += gNsISecTel.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_UNTRUSTED;
michael@0 354 }
michael@0 355 if (gSSLStatus.isDomainMismatch) {
michael@0 356 flags |= overrideService.ERROR_MISMATCH;
michael@0 357 confirmBucketId += gNsISecTel.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_DOMAIN;
michael@0 358 }
michael@0 359 if (gSSLStatus.isNotValidAtThisTime) {
michael@0 360 flags |= overrideService.ERROR_TIME;
michael@0 361 confirmBucketId += gNsISecTel.WARNING_BAD_CERT_TOP_CONFIRM_ADD_EXCEPTION_FLAG_TIME;
michael@0 362 }
michael@0 363
michael@0 364 var permanentCheckbox = document.getElementById("permanent");
michael@0 365 var shouldStorePermanently = permanentCheckbox.checked && !inPrivateBrowsingMode();
michael@0 366 if(!permanentCheckbox.checked)
michael@0 367 gSecHistogram.add(gNsISecTel.WARNING_BAD_CERT_TOP_DONT_REMEMBER_EXCEPTION);
michael@0 368
michael@0 369 gSecHistogram.add(confirmBucketId);
michael@0 370 var uri = getURI();
michael@0 371 overrideService.rememberValidityOverride(
michael@0 372 uri.asciiHost, uri.port,
michael@0 373 gCert,
michael@0 374 flags,
michael@0 375 !shouldStorePermanently);
michael@0 376
michael@0 377 var args = window.arguments;
michael@0 378 if (args && args[0])
michael@0 379 args[0].exceptionAdded = true;
michael@0 380
michael@0 381 gDialog.acceptDialog();
michael@0 382 }
michael@0 383
michael@0 384 /**
michael@0 385 * Returns true if this dialog is in private browsing mode.
michael@0 386 */
michael@0 387 function inPrivateBrowsingMode() {
michael@0 388 return PrivateBrowsingUtils.isWindowPrivate(window);
michael@0 389 }

mercurial