summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/extensions/smime/certFetchingStatus.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/extensions/smime/certFetchingStatus.js')
-rw-r--r--comm/mailnews/extensions/smime/certFetchingStatus.js255
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();
+ }
+}