diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/extensions/smime/certFetchingStatus.js | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/extensions/smime/certFetchingStatus.js | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/comm/mailnews/extensions/smime/certFetchingStatus.js b/comm/mailnews/extensions/smime/certFetchingStatus.js new file mode 100644 index 0000000000..ea7cd63226 --- /dev/null +++ b/comm/mailnews/extensions/smime/certFetchingStatus.js @@ -0,0 +1,255 @@ +/* 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/. */ + +let USER_CERT_ATTRIBUTE = "usercertificate;binary"; + +let gEmailAddresses; +let gDirectoryPref; +let gLdapServerURL; +let gLdapConnection; +let gCertDB; +let gLdapOperation; +let gLogin; + +window.addEventListener("DOMContentLoaded", onLoad); +document.addEventListener("dialogcancel", stopFetching); + +/** + * Expects the following arguments: + * - pref name of LDAP directory to fetch from + * - array with email addresses + * + * Display modal dialog with message and stop button. + * In onload, kick off binding to LDAP. + * When bound, kick off the searches. + * On finding certificates, import into permanent cert database. + * When all searches are finished, close the dialog. + */ +function onLoad() { + gDirectoryPref = window.arguments[0]; + gEmailAddresses = window.arguments[1]; + + if (!gEmailAddresses.length) { + window.close(); + return; + } + + setTimeout(search); +} + +function search() { + // Get the login to authenticate as, if there is one. No big deal if we don't + // have one. + gLogin = Services.prefs.getStringPref(gDirectoryPref + ".auth.dn", undefined); + + try { + let url = Services.prefs.getCharPref(gDirectoryPref + ".uri"); + + gLdapServerURL = Services.io.newURI(url).QueryInterface(Ci.nsILDAPURL); + + gLdapConnection = Cc["@mozilla.org/network/ldap-connection;1"] + .createInstance() + .QueryInterface(Ci.nsILDAPConnection); + + gLdapConnection.init( + gLdapServerURL, + gLogin, + new BindListener(), + null, + Ci.nsILDAPConnection.VERSION3 + ); + } catch (ex) { + console.error(ex); + window.close(); + } +} + +function stopFetching() { + if (gLdapOperation) { + try { + gLdapOperation.abandon(); + } catch (e) {} + } +} + +function importCert(ber_value) { + if (!gCertDB) { + gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + } + + // ber_value has type nsILDAPBERValue + let cert_bytes = ber_value.get(); + if (cert_bytes) { + gCertDB.importEmailCertificate(cert_bytes, cert_bytes.length, null); + } +} + +function getLDAPOperation() { + gLdapOperation = Cc["@mozilla.org/network/ldap-operation;1"].createInstance( + Ci.nsILDAPOperation + ); + + gLdapOperation.init(gLdapConnection, new LDAPMessageListener(), null); +} + +async function getPassword() { + // we only need a password if we are using credentials + if (!gLogin) { + return null; + } + let authPrompter = Services.ww.getNewAuthPrompter(window); + let strBundle = document.getElementById("bundle_ldap"); + let password = { value: "" }; + + // nsLDAPAutocompleteSession uses asciiHost instead of host for the prompt + // text, I think we should be consistent. + if ( + await authPrompter.asyncPromptPassword( + strBundle.getString("authPromptTitle"), + strBundle.getFormattedString("authPromptText", [ + gLdapServerURL.asciiHost, + ]), + gLdapServerURL.spec, + authPrompter.SAVE_PASSWORD_PERMANENTLY, + password + ) + ) { + return password.value; + } + return null; +} + +/** + * Checks if the LDAP connection can be bound. + * @implements {nsILDAPMessageListener} + */ +class BindListener { + QueryInterface = ChromeUtils.generateQI(["nsILDAPMessageListener"]); + + async onLDAPInit(conn, status) { + // Kick off bind. + getLDAPOperation(); + gLdapOperation.simpleBind(await getPassword()); + } + + onLDAPMessage(message) {} + + onLDAPError(status, secInfo, location) { + if (secInfo) { + console.warn(`LDAP bind connection security error for ${location}`); + } else { + console.warn(`LDAP bind error: ${status}`); + } + window.close(); + } +} + +/** + * LDAPMessageListener. + * @implements {nsILDAPMessageListener} + */ +class LDAPMessageListener { + QueryInterface = ChromeUtils.generateQI(["nsILDAPMessageListener"]); + + onLDAPInit(conn, status) {} + + onLDAPMessage(message) { + if (Ci.nsILDAPMessage.RES_SEARCH_RESULT == message.type) { + window.close(); + return; + } + + if (Ci.nsILDAPMessage.RES_BIND == message.type) { + if (Ci.nsILDAPErrors.SUCCESS != message.errorCode) { + window.close(); + return; + } + // Kick off search. + let prefix1 = ""; + let suffix1 = ""; + + let urlFilter = gLdapServerURL.filter; + if ( + urlFilter != null && + urlFilter.length > 0 && + urlFilter != "(objectclass=*)" + ) { + if (urlFilter.startsWith("(")) { + prefix1 = "(&" + urlFilter; + } else { + prefix1 = "(&(" + urlFilter + ")"; + } + suffix1 = ")"; + } + + let prefix2 = ""; + let suffix2 = ""; + + if (gEmailAddresses.length > 1) { + prefix2 = "(|"; + suffix2 = ")"; + } + + let mailFilter = ""; + + for (let email of gEmailAddresses) { + mailFilter += "(mail=" + email + ")"; + } + + let filter = prefix1 + prefix2 + mailFilter + suffix2 + suffix1; + + // Max search results => + // Double number of email addresses, because each person might have + // multiple certificates listed. We expect at most two certificates, + // one for signing, one for encrypting. + // Maybe that number should be larger, to allow for deployments, + // where even more certs can be stored per user??? + + let maxEntriesWanted = gEmailAddresses.length * 2; + + getLDAPOperation(); + gLdapOperation.searchExt( + gLdapServerURL.dn, + gLdapServerURL.scope, + filter, + USER_CERT_ATTRIBUTE, + 0, + maxEntriesWanted + ); + return; + } + + if (Ci.nsILDAPMessage.RES_SEARCH_ENTRY == message.type) { + let outBinValues = null; + try { + // This call may throw if the result message is empty or doesn't + // contain this attribute. + // It's an allowed condition that the attribute is missing on + // the server, so we silently ignore a failure to obtain it. + outBinValues = message.getBinaryValues(USER_CERT_ATTRIBUTE); + } catch (ex) {} + if (outBinValues) { + for (let i = 0; i < outBinValues.length; ++i) { + importCert(outBinValues[i]); + } + } + } + } + + /** + * @param {nsresult} status + * @param {?nsITransportSecurityInfo} secInfo + * @param {?string} location + */ + onLDAPError(status, secInfo, location) { + if (secInfo) { + console.warn(`LDAP connection security error for ${location}`); + } else { + console.warn(`LDAP error: ${status}`); + } + window.close(); + } +} |