diff options
Diffstat (limited to 'mailnews/extensions/smime/content/am-smime.js')
-rw-r--r-- | mailnews/extensions/smime/content/am-smime.js | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/mailnews/extensions/smime/content/am-smime.js b/mailnews/extensions/smime/content/am-smime.js new file mode 100644 index 000000000..4a90d0cd7 --- /dev/null +++ b/mailnews/extensions/smime/content/am-smime.js @@ -0,0 +1,478 @@ +/* -*- 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();"); +} + |