mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-11 09:47:32 +09:00
This avoids getting data synchronously on the main thread in an XHR (which has been deprecated for a long time and _may_ actually be blocked in our networking) and attempts to be more predictable by always firing an update request for the dialog from the XHR request handlers.
328 lines
10 KiB
JavaScript
328 lines
10 KiB
JavaScript
/* 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/. */
|
|
/* import-globals-from pippki.js */
|
|
"use strict";
|
|
|
|
var gDialog;
|
|
var gBundleBrand;
|
|
var gPKIBundle;
|
|
var gSSLStatus;
|
|
var gCert;
|
|
var gChecking;
|
|
var gBroken;
|
|
var gNeedReset;
|
|
|
|
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
|
|
|
|
function initExceptionDialog() {
|
|
gNeedReset = false;
|
|
gDialog = document.documentElement;
|
|
gBundleBrand = document.getElementById("brand_bundle");
|
|
gPKIBundle = document.getElementById("pippki_bundle");
|
|
|
|
var brandName = gBundleBrand.getString("brandShortName");
|
|
setText("warningText", gPKIBundle.getFormattedString("addExceptionBrandedWarning2", [brandName]));
|
|
gDialog.getButton("extra1").disabled = true;
|
|
|
|
var args = window.arguments;
|
|
if (args && args[0]) {
|
|
if (args[0].location) {
|
|
// We were pre-seeded with a location.
|
|
document.getElementById("locationTextBox").value = args[0].location;
|
|
document.getElementById('checkCertButton').disabled = false;
|
|
|
|
if (args[0].sslStatus) {
|
|
gSSLStatus = args[0].sslStatus;
|
|
gCert = gSSLStatus.serverCert;
|
|
gBroken = true;
|
|
updateCertStatus();
|
|
} else if (args[0].prefetchCert) {
|
|
// We can optionally pre-fetch the certificate too. Don't do this
|
|
// synchronously, since it would prevent the window from appearing
|
|
// until the fetch is completed, which could be multiple seconds.
|
|
// Instead, let's use a timer to spawn the actual fetch, but update
|
|
// the dialog to "checking..." state right away, so that the UI
|
|
// is appropriately responsive. Bug 453855
|
|
document.getElementById("checkCertButton").disabled = true;
|
|
gChecking = true;
|
|
updateCertStatus();
|
|
|
|
window.setTimeout(checkCert, 0);
|
|
}
|
|
}
|
|
|
|
// Set out parameter to false by default
|
|
args[0].exceptionAdded = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function for checkCert. Set as the onerror/onload callbacks for an
|
|
* XMLHttpRequest. Sets gSSLStatus, gCert, gBroken, and gChecking according to
|
|
* the load information from the request. Probably should not be used directly.
|
|
*
|
|
* @param {XMLHttpRequest} req
|
|
* The XMLHttpRequest created and sent by checkCert.
|
|
* @param {Event} evt
|
|
* The load or error event.
|
|
*/
|
|
function grabCert(req, evt) {
|
|
if (req.channel && req.channel.securityInfo) {
|
|
gSSLStatus = req.channel.securityInfo
|
|
.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
|
|
gCert = gSSLStatus ? gSSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert
|
|
: null;
|
|
}
|
|
gBroken = evt.type == "error";
|
|
gChecking = false;
|
|
updateCertStatus();
|
|
}
|
|
|
|
/**
|
|
* Attempt to download the certificate for the location specified, and populate
|
|
* the Certificate Status section with the result.
|
|
*/
|
|
function checkCert() {
|
|
gCert = null;
|
|
gSSLStatus = null;
|
|
gChecking = true;
|
|
gBroken = false;
|
|
updateCertStatus();
|
|
|
|
let uri = getURI();
|
|
|
|
if (uri) {
|
|
let req = new XMLHttpRequest();
|
|
req.open("GET", uri.prePath);
|
|
req.onerror = grabCert.bind(this, req);
|
|
req.onload = grabCert.bind(this, req);
|
|
req.send(null);
|
|
} else {
|
|
gChecking = false;
|
|
updateCertStatus();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build and return a URI, based on the information supplied in the
|
|
* Certificate Location fields
|
|
*/
|
|
function getURI() {
|
|
// Use fixup service instead of just ioservice's newURI since it's quite
|
|
// likely that the host will be supplied without a protocol prefix, resulting
|
|
// in malformed uri exceptions being thrown.
|
|
let fus = Components.classes["@mozilla.org/docshell/urifixup;1"]
|
|
.getService(Components.interfaces.nsIURIFixup);
|
|
let locationTextBox = document.getElementById("locationTextBox");
|
|
let uri = fus.createFixupURI(locationTextBox.value, 0);
|
|
|
|
if (!uri) {
|
|
return null;
|
|
}
|
|
|
|
if (uri.scheme == "http") {
|
|
uri.scheme = "https";
|
|
}
|
|
|
|
if (uri.port == -1) {
|
|
uri.port = 443;
|
|
}
|
|
|
|
return uri;
|
|
}
|
|
|
|
function resetDialog() {
|
|
document.getElementById("viewCertButton").disabled = true;
|
|
document.getElementById("permanent").disabled = true;
|
|
gDialog.getButton("extra1").disabled = true;
|
|
setText("headerDescription", "");
|
|
setText("statusDescription", "");
|
|
setText("statusLongDescription", "");
|
|
setText("status2Description", "");
|
|
setText("status2LongDescription", "");
|
|
setText("status3Description", "");
|
|
setText("status3LongDescription", "");
|
|
}
|
|
|
|
/**
|
|
* Called by input textboxes to manage UI state
|
|
*/
|
|
function handleTextChange() {
|
|
var checkCertButton = document.getElementById('checkCertButton');
|
|
checkCertButton.disabled = !(document.getElementById("locationTextBox").value);
|
|
if (gNeedReset) {
|
|
gNeedReset = false;
|
|
resetDialog();
|
|
}
|
|
}
|
|
|
|
function updateCertStatus() {
|
|
var shortDesc, longDesc;
|
|
var shortDesc2, longDesc2;
|
|
var shortDesc3, longDesc3;
|
|
var use2 = false;
|
|
var use3 = false;
|
|
if (gCert) {
|
|
if (gBroken) {
|
|
var mms = "addExceptionDomainMismatchShort";
|
|
var mml = "addExceptionDomainMismatchLong2";
|
|
var exs = "addExceptionExpiredShort";
|
|
var exl = "addExceptionExpiredLong2";
|
|
var uts = "addExceptionUnverifiedOrBadSignatureShort";
|
|
var utl = "addExceptionUnverifiedOrBadSignatureLong2";
|
|
var use1 = false;
|
|
if (gSSLStatus.isDomainMismatch) {
|
|
use1 = true;
|
|
shortDesc = mms;
|
|
longDesc = mml;
|
|
}
|
|
if (gSSLStatus.isNotValidAtThisTime) {
|
|
if (!use1) {
|
|
use1 = true;
|
|
shortDesc = exs;
|
|
longDesc = exl;
|
|
}
|
|
else {
|
|
use2 = true;
|
|
shortDesc2 = exs;
|
|
longDesc2 = exl;
|
|
}
|
|
}
|
|
if (gSSLStatus.isUntrusted) {
|
|
if (!use1) {
|
|
use1 = true;
|
|
shortDesc = uts;
|
|
longDesc = utl;
|
|
} else if (!use2) {
|
|
use2 = true;
|
|
shortDesc2 = uts;
|
|
longDesc2 = utl;
|
|
} else {
|
|
use3 = true;
|
|
shortDesc3 = uts;
|
|
longDesc3 = utl;
|
|
}
|
|
}
|
|
|
|
// In these cases, we do want to enable the "Add Exception" button
|
|
gDialog.getButton("extra1").disabled = false;
|
|
|
|
// If the Private Browsing service is available and the mode is active,
|
|
// don't store permanent exceptions, since they would persist after
|
|
// private browsing mode was disabled.
|
|
var inPrivateBrowsing = inPrivateBrowsingMode();
|
|
var pe = document.getElementById("permanent");
|
|
pe.disabled = inPrivateBrowsing;
|
|
pe.checked = !inPrivateBrowsing;
|
|
|
|
setText("headerDescription", gPKIBundle.getString("addExceptionInvalidHeader"));
|
|
}
|
|
else {
|
|
shortDesc = "addExceptionValidShort";
|
|
longDesc = "addExceptionValidLong";
|
|
gDialog.getButton("extra1").disabled = true;
|
|
document.getElementById("permanent").disabled = true;
|
|
}
|
|
|
|
// We're done checking the certificate, so allow the user to check it again.
|
|
document.getElementById("checkCertButton").disabled = false;
|
|
document.getElementById("viewCertButton").disabled = false;
|
|
|
|
// Notify observers about the availability of the certificate
|
|
Components.classes["@mozilla.org/observer-service;1"]
|
|
.getService(Components.interfaces.nsIObserverService)
|
|
.notifyObservers(null, "cert-exception-ui-ready", null);
|
|
}
|
|
else if (gChecking) {
|
|
shortDesc = "addExceptionCheckingShort";
|
|
longDesc = "addExceptionCheckingLong2";
|
|
// We're checking the certificate, so we disable the Get Certificate
|
|
// button to make sure that the user can't interrupt the process and
|
|
// trigger another certificate fetch.
|
|
document.getElementById("checkCertButton").disabled = true;
|
|
document.getElementById("viewCertButton").disabled = true;
|
|
gDialog.getButton("extra1").disabled = true;
|
|
document.getElementById("permanent").disabled = true;
|
|
}
|
|
else {
|
|
shortDesc = "addExceptionNoCertShort";
|
|
longDesc = "addExceptionNoCertLong2";
|
|
// We're done checking the certificate, so allow the user to check it again.
|
|
document.getElementById("checkCertButton").disabled = false;
|
|
document.getElementById("viewCertButton").disabled = true;
|
|
gDialog.getButton("extra1").disabled = true;
|
|
document.getElementById("permanent").disabled = true;
|
|
}
|
|
|
|
setText("statusDescription", gPKIBundle.getString(shortDesc));
|
|
setText("statusLongDescription", gPKIBundle.getString(longDesc));
|
|
|
|
if (use2) {
|
|
setText("status2Description", gPKIBundle.getString(shortDesc2));
|
|
setText("status2LongDescription", gPKIBundle.getString(longDesc2));
|
|
}
|
|
|
|
if (use3) {
|
|
setText("status3Description", gPKIBundle.getString(shortDesc3));
|
|
setText("status3LongDescription", gPKIBundle.getString(longDesc3));
|
|
}
|
|
|
|
gNeedReset = true;
|
|
}
|
|
|
|
/**
|
|
* Handle user request to display certificate details
|
|
*/
|
|
function viewCertButtonClick() {
|
|
if (gCert) {
|
|
viewCertHelper(this, gCert);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle user request to add an exception for the specified cert
|
|
*/
|
|
function addException() {
|
|
if (!gCert || !gSSLStatus) {
|
|
return;
|
|
}
|
|
|
|
var overrideService = Components.classes["@mozilla.org/security/certoverride;1"]
|
|
.getService(Components.interfaces.nsICertOverrideService);
|
|
var flags = 0;
|
|
if (gSSLStatus.isUntrusted) {
|
|
flags |= overrideService.ERROR_UNTRUSTED;
|
|
}
|
|
if (gSSLStatus.isDomainMismatch) {
|
|
flags |= overrideService.ERROR_MISMATCH;
|
|
}
|
|
if (gSSLStatus.isNotValidAtThisTime) {
|
|
flags |= overrideService.ERROR_TIME;
|
|
}
|
|
|
|
var permanentCheckbox = document.getElementById("permanent");
|
|
var shouldStorePermanently = permanentCheckbox.checked && !inPrivateBrowsingMode();
|
|
|
|
var uri = getURI();
|
|
overrideService.rememberValidityOverride(
|
|
uri.asciiHost, uri.port,
|
|
gCert,
|
|
flags,
|
|
!shouldStorePermanently);
|
|
|
|
let args = window.arguments;
|
|
if (args && args[0]) {
|
|
args[0].exceptionAdded = true;
|
|
}
|
|
|
|
gDialog.acceptDialog();
|
|
}
|
|
|
|
/**
|
|
* Returns true if this dialog is in private browsing mode.
|
|
*/
|
|
function inPrivateBrowsingMode() {
|
|
return PrivateBrowsingUtils.isWindowPrivate(window);
|
|
}
|