Dactyloidae/mailnews/extensions/smime/content/am-smime.js

478 lines
15 KiB
JavaScript

/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
var nsIX509CertDB = Components.interfaces.nsIX509CertDB;
var nsX509CertDBContractID = "@mozilla.org/security/x509certdb;1";
var nsIX509Cert = Components.interfaces.nsIX509Cert;
var email_recipient_cert_usage = 5;
var email_signing_cert_usage = 4;
var gIdentity;
var gPref = null;
var gEncryptionCertName = null;
var gHiddenEncryptionPolicy = null;
var gEncryptionChoices = null;
var gSignCertName = null;
var gSignMessages = null;
var gEncryptAlways = null;
var gNeverEncrypt = null;
var gBundle = null;
var gBrandBundle;
var gSmimePrefbranch;
var gEncryptionChoicesLocked;
var gSigningChoicesLocked;
var kEncryptionCertPref = "identity.encryption_cert_name";
var kSigningCertPref = "identity.signing_cert_name";
function onInit()
{
smimeInitializeFields();
}
function smimeInitializeFields()
{
// initialize all of our elements based on the current identity values....
gEncryptionCertName = document.getElementById(kEncryptionCertPref);
gHiddenEncryptionPolicy = document.getElementById("identity.encryptionpolicy");
gEncryptionChoices = document.getElementById("encryptionChoices");
gSignCertName = document.getElementById(kSigningCertPref);
gSignMessages = document.getElementById("identity.sign_mail");
gEncryptAlways = document.getElementById("encrypt_mail_always");
gNeverEncrypt = document.getElementById("encrypt_mail_never");
gBundle = document.getElementById("bundle_smime");
gBrandBundle = document.getElementById("bundle_brand");
gEncryptionChoicesLocked = false;
gSigningChoicesLocked = false;
if (!gIdentity) {
// The user is going to create a new identity.
// Set everything to default values.
// Do not take over the values from gAccount.defaultIdentity
// as the new identity is going to have a different mail address.
gEncryptionCertName.value = "";
gEncryptionCertName.nickname = "";
gEncryptionCertName.dbKey = "";
gSignCertName.value = "";
gSignCertName.nickname = "";
gSignCertName.dbKey = "";
gEncryptAlways.setAttribute("disabled", true);
gNeverEncrypt.setAttribute("disabled", true);
gSignMessages.setAttribute("disabled", true);
gSignMessages.checked = false;
gEncryptionChoices.value = 0;
}
else {
var certdb = Components.classes[nsX509CertDBContractID].getService(nsIX509CertDB);
var x509cert = null;
gEncryptionCertName.value = gIdentity.getUnicharAttribute("encryption_cert_name");
gEncryptionCertName.dbKey = gIdentity.getCharAttribute("encryption_cert_dbkey");
// If we succeed in looking up the certificate by the dbkey pref, then
// append the serial number " [...]" to the display value, and remember the
// nickname in a separate property.
try {
if (certdb && gEncryptionCertName.dbKey &&
(x509cert = certdb.findCertByDBKey(gEncryptionCertName.dbKey))) {
gEncryptionCertName.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
gEncryptionCertName.nickname = x509cert.nickname;
}
} catch(e) {}
gEncryptionChoices.value = gIdentity.getIntAttribute("encryptionpolicy");
if (!gEncryptionCertName.value) {
gEncryptAlways.setAttribute("disabled", true);
gNeverEncrypt.setAttribute("disabled", true);
}
else {
enableEncryptionControls(true);
}
gSignCertName.value = gIdentity.getUnicharAttribute("signing_cert_name");
gSignCertName.dbKey = gIdentity.getCharAttribute("signing_cert_dbkey");
x509cert = null;
// same procedure as with gEncryptionCertName (see above)
try {
if (certdb && gSignCertName.dbKey &&
(x509cert = certdb.findCertByDBKey(gSignCertName.dbKey))) {
gSignCertName.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
gSignCertName.nickname = x509cert.nickname;
}
} catch(e) {}
gSignMessages.checked = gIdentity.getBoolAttribute("sign_mail");
if (!gSignCertName.value)
{
gSignMessages.setAttribute("disabled", true);
}
else {
enableSigningControls(true);
}
}
// Always start with enabling signing and encryption cert select buttons.
// This will keep the visibility of buttons in a sane state as user
// jumps from security panel of one account to another.
enableCertSelectButtons();
// Disable all locked elements on the panel
if (gIdentity)
onLockPreference();
}
function onPreInit(account, accountValues)
{
gIdentity = account.defaultIdentity;
}
function onSave()
{
smimeSave();
}
function smimeSave()
{
// find out which radio for the encryption radio group is selected and set that on our hidden encryptionChoice pref....
var newValue = gEncryptionChoices.value;
gHiddenEncryptionPolicy.setAttribute('value', newValue);
gIdentity.setIntAttribute("encryptionpolicy", newValue);
gIdentity.setUnicharAttribute("encryption_cert_name",
gEncryptionCertName.nickname || gEncryptionCertName.value);
gIdentity.setCharAttribute("encryption_cert_dbkey", gEncryptionCertName.dbKey);
gIdentity.setBoolAttribute("sign_mail", gSignMessages.checked);
gIdentity.setUnicharAttribute("signing_cert_name",
gSignCertName.nickname || gSignCertName.value);
gIdentity.setCharAttribute("signing_cert_dbkey", gSignCertName.dbKey);
}
function smimeOnAcceptEditor()
{
try {
if (!onOk())
return false;
}
catch (ex) {}
smimeSave();
return true;
}
function onLockPreference()
{
var initPrefString = "mail.identity";
var finalPrefString;
var allPrefElements = [
{ prefstring:"signingCertSelectButton", id:"signingCertSelectButton"},
{ prefstring:"encryptionCertSelectButton", id:"encryptionCertSelectButton"},
{ prefstring:"sign_mail", id:"identity.sign_mail"},
{ prefstring:"encryptionpolicy", id:"encryptionChoices"}
];
finalPrefString = initPrefString + "." + gIdentity.key + ".";
gSmimePrefbranch = Services.prefs.getBranch(finalPrefString);
disableIfLocked( allPrefElements );
}
// Does the work of disabling an element given the array which contains xul id/prefstring pairs.
// Also saves the id/locked state in an array so that other areas of the code can avoid
// stomping on the disabled state indiscriminately.
function disableIfLocked( prefstrArray )
{
var i;
for (i=0; i<prefstrArray.length; i++) {
var id = prefstrArray[i].id;
var element = document.getElementById(id);
if (gSmimePrefbranch.prefIsLocked(prefstrArray[i].prefstring)) {
// If encryption choices radio group is locked, make sure the individual
// choices in the group are locked. Set a global (gEncryptionChoicesLocked)
// indicating the status so that locking can be maintained further.
if (id == "encryptionChoices") {
document.getElementById("encrypt_mail_never").setAttribute("disabled", "true");
document.getElementById("encrypt_mail_always").setAttribute("disabled", "true");
gEncryptionChoicesLocked = true;
}
// If option to sign mail is locked (with true/false set in config file), disable
// the corresponding checkbox and set a global (gSigningChoicesLocked) in order to
// honor the locking as user changes other elements on the panel.
if (id == "identity.sign_mail") {
document.getElementById("identity.sign_mail").setAttribute("disabled", "true");
gSigningChoicesLocked = true;
}
else {
element.setAttribute("disabled", "true");
if (id == "signingCertSelectButton") {
document.getElementById("signingCertClearButton").setAttribute("disabled", "true");
}
else if (id == "encryptionCertSelectButton") {
document.getElementById("encryptionCertClearButton").setAttribute("disabled", "true");
}
}
}
}
}
function alertUser(message)
{
Services.prompt.alert(window,
gBrandBundle.getString("brandShortName"),
message);
}
function askUser(message)
{
let button = Services.prompt.confirmEx(
window,
gBrandBundle.getString("brandShortName"),
message,
Services.prompt.STD_YES_NO_BUTTONS,
null,
null,
null,
null,
{});
// confirmEx returns button index:
return (button == 0);
}
function checkOtherCert(cert, pref, usage, msgNeedCertWantSame, msgWantSame, msgNeedCertWantToSelect, enabler)
{
var otherCertInfo = document.getElementById(pref);
if (!otherCertInfo)
return;
if (otherCertInfo.dbKey == cert.dbKey)
// all is fine, same cert is now selected for both purposes
return;
var certdb = Components.classes[nsX509CertDBContractID].getService(nsIX509CertDB);
if (!certdb)
return;
if (email_recipient_cert_usage == usage) {
matchingOtherCert = certdb.findEmailEncryptionCert(cert.nickname);
}
else if (email_signing_cert_usage == usage) {
matchingOtherCert = certdb.findEmailSigningCert(cert.nickname);
}
else
return;
var userWantsSameCert = false;
if (!otherCertInfo.value.length) {
if (matchingOtherCert && (matchingOtherCert.dbKey == cert.dbKey)) {
userWantsSameCert = askUser(gBundle.getString(msgNeedCertWantSame));
}
else {
if (askUser(gBundle.getString(msgNeedCertWantToSelect))) {
smimeSelectCert(pref);
}
}
}
else {
if (matchingOtherCert && (matchingOtherCert.dbKey == cert.dbKey)) {
userWantsSameCert = askUser(gBundle.getString(msgWantSame));
}
}
if (userWantsSameCert) {
otherCertInfo.value = cert.nickname + " [" + cert.serialNumber + "]";
otherCertInfo.nickname = cert.nickname;
otherCertInfo.dbKey = cert.dbKey;
enabler(true);
}
}
function smimeSelectCert(smime_cert)
{
var certInfo = document.getElementById(smime_cert);
if (!certInfo)
return;
var picker = Components.classes["@mozilla.org/user_cert_picker;1"]
.createInstance(Components.interfaces.nsIUserCertPicker);
var canceled = new Object;
var x509cert = 0;
var certUsage;
var selectEncryptionCert;
if (smime_cert == kEncryptionCertPref) {
selectEncryptionCert = true;
certUsage = email_recipient_cert_usage;
} else if (smime_cert == kSigningCertPref) {
selectEncryptionCert = false;
certUsage = email_signing_cert_usage;
}
try {
x509cert = picker.pickByUsage(window,
certInfo.value,
certUsage, // this is from enum SECCertUsage
false, true,
gIdentity.email,
canceled);
} catch(e) {
canceled.value = false;
x509cert = null;
}
if (!canceled.value) {
if (!x509cert) {
if (gIdentity.email) {
alertUser(gBundle.getFormattedString(selectEncryptionCert ?
"NoEncryptionCertForThisAddress" :
"NoSigningCertForThisAddress",
[ gIdentity.email ]));
} else {
alertUser(gBundle.getString(selectEncryptionCert ?
"NoEncryptionCert" : "NoSigningCert"));
}
}
else {
certInfo.removeAttribute("disabled");
certInfo.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
certInfo.nickname = x509cert.nickname;
certInfo.dbKey = x509cert.dbKey;
if (selectEncryptionCert) {
enableEncryptionControls(true);
checkOtherCert(x509cert,
kSigningCertPref, email_signing_cert_usage,
"signing_needCertWantSame",
"signing_wantSame",
"signing_needCertWantToSelect",
enableSigningControls);
} else {
enableSigningControls(true);
checkOtherCert(x509cert,
kEncryptionCertPref, email_recipient_cert_usage,
"encryption_needCertWantSame",
"encryption_wantSame",
"encryption_needCertWantToSelect",
enableEncryptionControls);
}
}
}
enableCertSelectButtons();
}
function enableEncryptionControls(do_enable)
{
if (gEncryptionChoicesLocked)
return;
if (do_enable) {
gEncryptAlways.removeAttribute("disabled");
gNeverEncrypt.removeAttribute("disabled");
gEncryptionCertName.removeAttribute("disabled");
}
else {
gEncryptAlways.setAttribute("disabled", "true");
gNeverEncrypt.setAttribute("disabled", "true");
gEncryptionCertName.setAttribute("disabled", "true");
gEncryptionChoices.value = 0;
}
}
function enableSigningControls(do_enable)
{
if (gSigningChoicesLocked)
return;
if (do_enable) {
gSignMessages.removeAttribute("disabled");
gSignCertName.removeAttribute("disabled");
}
else {
gSignMessages.setAttribute("disabled", "true");
gSignCertName.setAttribute("disabled", "true");
gSignMessages.checked = false;
}
}
function enableCertSelectButtons()
{
document.getElementById("signingCertSelectButton").removeAttribute("disabled");
if (document.getElementById('identity.signing_cert_name').value.length)
document.getElementById("signingCertClearButton").removeAttribute("disabled");
else
document.getElementById("signingCertClearButton").setAttribute("disabled", "true");
document.getElementById("encryptionCertSelectButton").removeAttribute("disabled");
if (document.getElementById('identity.encryption_cert_name').value.length)
document.getElementById("encryptionCertClearButton").removeAttribute("disabled");
else
document.getElementById("encryptionCertClearButton").setAttribute("disabled", "true");
}
function smimeClearCert(smime_cert)
{
var certInfo = document.getElementById(smime_cert);
if (!certInfo)
return;
certInfo.setAttribute("disabled", "true");
certInfo.value = "";
certInfo.nickname = "";
certInfo.dbKey = "";
if (smime_cert == kEncryptionCertPref) {
enableEncryptionControls(false);
} else if (smime_cert == kSigningCertPref) {
enableSigningControls(false);
}
enableCertSelectButtons();
}
function openCertManager()
{
// Check for an existing certManager window and focus it; it's not
// application modal.
let lastCertManager = Services.wm.getMostRecentWindow("mozilla:certmanager");
if (lastCertManager)
lastCertManager.focus();
else
window.openDialog("chrome://pippki/content/certManager.xul", "",
"centerscreen,resizable=yes,dialog=no");
}
function openDeviceManager()
{
// Check for an existing deviceManager window and focus it; it's not
// application modal.
let lastCertManager = Services.wm.getMostRecentWindow("mozilla:devicemanager");
if (lastCertManager)
lastCertManager.focus();
else
window.openDialog("chrome://pippki/content/device_manager.xul", "",
"centerscreen,resizable=yes,dialog=no");
}
function smimeOnLoadEditor()
{
smimeInitializeFields();
document.documentElement.setAttribute("ondialogaccept",
"return smimeOnAcceptEditor();");
}