Bug 1644085 - Support recipient aliases for OpenPGP encryption. r=mkmelin
Differential Revision: https://phabricator.services.mozilla.com/D97973 --HG-- extra : rebase_source : ecb59884c807ba4f3e7a0c422889b31e7a316b98
This commit is contained in:
Родитель
35969d5191
Коммит
ad40ff5527
|
@ -36,6 +36,12 @@ pref("mail.identity.default.is_gnupg_key_id", false);
|
|||
// The hexadecimal OpenPGP key ID externally configured by GnuPG used for an identity.
|
||||
pref("mail.identity.default.last_entered_external_gnupg_key_id", "");
|
||||
|
||||
// Load a JSON file that contains recipient key alias rules. See bug 1644085.
|
||||
// Suggested filename: openpgp-alias-rules.json
|
||||
// Simple filenames (without path) are loaded from the profile directory.
|
||||
// If you need to specify a path, use a file:// URL
|
||||
pref("mail.openpgp.alias_rules_file", "");
|
||||
|
||||
// When sending, encrypt to this additional key. Not available in release channel builds.
|
||||
pref("mail.openpgp.debug.extra_encryption_key", "");
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/* 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/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ["OpenPGPAlias"];
|
||||
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
var OpenPGPAlias = {
|
||||
_aliasDomains: null,
|
||||
_aliasEmails: null,
|
||||
|
||||
_loaded() {
|
||||
return this._aliasDomains && this._aliasEmails;
|
||||
},
|
||||
|
||||
async load() {
|
||||
let path = Services.prefs.getStringPref(
|
||||
"mail.openpgp.alias_rules_file",
|
||||
""
|
||||
);
|
||||
|
||||
if (!path) {
|
||||
this._clear();
|
||||
return;
|
||||
}
|
||||
|
||||
await this._loadFromFile(path);
|
||||
},
|
||||
|
||||
_clear() {
|
||||
this._aliasDomains = new Map();
|
||||
this._aliasEmails = new Map();
|
||||
},
|
||||
|
||||
async _loadFromFile(src) {
|
||||
this._clear();
|
||||
|
||||
let aliasRules;
|
||||
let jsonData;
|
||||
if (src.startsWith("file://")) {
|
||||
let response = await fetch(src);
|
||||
jsonData = await response.json();
|
||||
} else if (src.includes("/") || src.includes("\\")) {
|
||||
throw new Error(`Invalid alias rules src: ${src}`);
|
||||
} else {
|
||||
let spec = OS.Path.join(OS.Constants.Path.profileDir, src);
|
||||
let response = await fetch(OS.Path.toFileURI(spec));
|
||||
jsonData = await response.json();
|
||||
}
|
||||
if (!("rules" in jsonData)) {
|
||||
throw new Error(
|
||||
"alias file contains invalid JSON data, no rules element found"
|
||||
);
|
||||
}
|
||||
aliasRules = jsonData.rules;
|
||||
|
||||
for (let entry of aliasRules) {
|
||||
if (!("keys" in entry)) {
|
||||
continue;
|
||||
}
|
||||
// Ignore duplicate rules, only use first rule per key.
|
||||
// Require email address contains @, and domain doesn't contain @.
|
||||
if ("email" in entry) {
|
||||
if (!entry.email.includes("@")) {
|
||||
console.log("Ignoring invalid email alias rule: " + entry.email);
|
||||
continue;
|
||||
}
|
||||
if (this._aliasEmails.get(entry.email)) {
|
||||
console.log("Ignoring duplicate email alias rule: " + entry.email);
|
||||
} else {
|
||||
this._aliasEmails.set(entry.email, entry.keys);
|
||||
}
|
||||
} else if ("domain" in entry) {
|
||||
if (entry.domain.includes("@")) {
|
||||
console.log("Ignoring invalid domain alias rule: " + entry.domain);
|
||||
continue;
|
||||
}
|
||||
if (this._aliasDomains.get(entry.domain)) {
|
||||
console.log("Ignoring duplicate domain alias rule: " + entry.domain);
|
||||
} else {
|
||||
this._aliasDomains.set(entry.domain, entry.keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDomainAliasKeyList(email) {
|
||||
if (!this._loaded()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let lastAt = email.lastIndexOf("@");
|
||||
if (lastAt == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let domain = email.substr(lastAt + 1);
|
||||
if (!domain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._aliasDomains.get(domain);
|
||||
},
|
||||
|
||||
getEmailAliasKeyList(email) {
|
||||
if (!this._loaded()) {
|
||||
return null;
|
||||
}
|
||||
return this._aliasEmails.get(email);
|
||||
},
|
||||
};
|
|
@ -2190,6 +2190,38 @@ var RNP = {
|
|||
}
|
||||
},
|
||||
|
||||
addAliasKeys(aliasKeys, op) {
|
||||
for (let ak of aliasKeys) {
|
||||
let key = this.getKeyHandleByKeyIdOrFingerprint(RNPLib.ffi, "0x" + ak);
|
||||
if (!key || key.isNull()) {
|
||||
console.debug(
|
||||
"addAliasKeys: cannot find key used by alias rule: " + ak
|
||||
);
|
||||
return false;
|
||||
}
|
||||
this.addSuitableEncryptKey(key, op);
|
||||
RNPLib.rnp_key_handle_destroy(key);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
async addEncryptionKeyForEmail(email, op) {
|
||||
let key = await this.findKeyByEmail(email, true);
|
||||
if (!key || key.isNull()) {
|
||||
return false;
|
||||
}
|
||||
this.addSuitableEncryptKey(key, op);
|
||||
RNPLib.rnp_key_handle_destroy(key);
|
||||
return true;
|
||||
},
|
||||
|
||||
getEmailWithoutBrackets(email) {
|
||||
if (email.startsWith("<") && email.endsWith(">")) {
|
||||
return email.substring(1, email.length - 1);
|
||||
}
|
||||
return email;
|
||||
},
|
||||
|
||||
async encryptAndOrSign(plaintext, args, resultStatus) {
|
||||
if (args.sign && args.senderKeyIsExternal) {
|
||||
if (!GPGME.allDependenciesLoaded()) {
|
||||
|
@ -2339,26 +2371,41 @@ var RNP = {
|
|||
}
|
||||
|
||||
if (args.encrypt) {
|
||||
// If we have an alias definition, it will be used, and the usual
|
||||
// lookup by email address will be skipped. Earlier code should
|
||||
// have already checked that alias keys are available and usable
|
||||
// for encryption, so we fail if a problem is found.
|
||||
|
||||
for (let id in args.to) {
|
||||
let toEmail = args.to[id].toLowerCase();
|
||||
let toKey = await this.findKeyByEmail(toEmail, true);
|
||||
if (!toKey || toKey.isNull()) {
|
||||
let aliasKeys = args.aliasKeys.get(
|
||||
this.getEmailWithoutBrackets(toEmail)
|
||||
);
|
||||
if (aliasKeys) {
|
||||
if (!this.addAliasKeys(aliasKeys, op)) {
|
||||
resultStatus.statusFlags |= EnigmailConstants.INVALID_RECIPIENT;
|
||||
return null;
|
||||
}
|
||||
} else if (!(await this.addEncryptionKeyForEmail(toEmail, op))) {
|
||||
resultStatus.statusFlags |= EnigmailConstants.INVALID_RECIPIENT;
|
||||
return null;
|
||||
}
|
||||
this.addSuitableEncryptKey(toKey, op);
|
||||
RNPLib.rnp_key_handle_destroy(toKey);
|
||||
}
|
||||
|
||||
for (let id in args.bcc) {
|
||||
let bccEmail = args.bcc[id].toLowerCase();
|
||||
let bccKey = await this.findKeyByEmail(bccEmail, true);
|
||||
if (bccKey.isNull()) {
|
||||
let aliasKeys = args.aliasKeys.get(
|
||||
this.getEmailWithoutBrackets(bccEmail)
|
||||
);
|
||||
if (aliasKeys) {
|
||||
if (!this.addAliasKeys(aliasKeys, op)) {
|
||||
resultStatus.statusFlags |= EnigmailConstants.INVALID_RECIPIENT;
|
||||
return null;
|
||||
}
|
||||
} else if (!(await this.addEncryptionKeyForEmail(bccEmail, op))) {
|
||||
resultStatus.statusFlags |= EnigmailConstants.INVALID_RECIPIENT;
|
||||
return null;
|
||||
}
|
||||
this.addSuitableEncryptKey(bccKey, op);
|
||||
RNPLib.rnp_key_handle_destroy(bccKey);
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_UPDATE_CHANNEL != "release") {
|
||||
|
@ -2477,7 +2524,7 @@ var RNP = {
|
|||
|
||||
async findKeyByEmail(id, onlyIfAcceptableAsRecipientKey = false) {
|
||||
if (!id.startsWith("<") || !id.endsWith(">") || id.includes(" ")) {
|
||||
throw new Error("invalid parameter given to findKeyByEmail");
|
||||
throw new Error(`Invalid argument; id=${id}`);
|
||||
}
|
||||
|
||||
let emailWithoutBrackets = id.substring(1, id.length - 1);
|
||||
|
|
|
@ -45,6 +45,7 @@ const ENC_TYPE_MSG = 0;
|
|||
const ENC_TYPE_ATTACH_BINARY = 1;
|
||||
|
||||
var EnigmailEncryption = {
|
||||
// return object on success, null on failure
|
||||
getCryptParams(
|
||||
fromMailAddr,
|
||||
toMailAddr,
|
||||
|
@ -100,6 +101,7 @@ var EnigmailEncryption = {
|
|||
|
||||
result.to = toMailAddr.split(/\s*,\s*/);
|
||||
result.bcc = bccMailAddr.split(/\s*,\s*/);
|
||||
result.aliasKeys = new Map();
|
||||
|
||||
if (result.to.length == 1 && result.to[0].length == 0) {
|
||||
result.to.splice(0, 1); // remove the single empty entry
|
||||
|
@ -111,7 +113,7 @@ var EnigmailEncryption = {
|
|||
|
||||
console.debug(`getCryptParams, got: to=${result.to}, bcc=${result.bcc}`);
|
||||
|
||||
if (fromMailAddr.search(/^0x/) === 0) {
|
||||
if (/^0x[0-9a-f]+$/i.test(fromMailAddr)) {
|
||||
result.sender = fromMailAddr;
|
||||
} else {
|
||||
result.sender = "<" + fromMailAddr + ">";
|
||||
|
@ -136,18 +138,36 @@ var EnigmailEncryption = {
|
|||
result.encryptToSender = true;
|
||||
}
|
||||
|
||||
var k;
|
||||
for (k = 0; k < result.to.length; k++) {
|
||||
//result.to[k] = result.to[k].replace(/'/g, "\\'");
|
||||
if (result.to[k].length > 0 && result.to[k].search(/^0x/) !== 0) {
|
||||
result.to[k] = "<" + result.to[k] + ">";
|
||||
let recipArrays = ["to", "bcc"];
|
||||
for (let recipArray of recipArrays) {
|
||||
let kMax = recipArray == "to" ? result.to.length : result.bcc.length;
|
||||
for (let k = 0; k < kMax; k++) {
|
||||
let email = recipArray == "to" ? result.to[k] : result.bcc[k];
|
||||
if (!email) {
|
||||
continue;
|
||||
}
|
||||
if (/^0x[0-9a-f]+$/i.test(email)) {
|
||||
throw new Error(`Recipient should not be a key ID: ${email}`);
|
||||
}
|
||||
if (recipArray == "to") {
|
||||
result.to[k] = "<" + email + ">";
|
||||
} else {
|
||||
result.bcc[k] = "<" + email + ">";
|
||||
}
|
||||
|
||||
for (k = 0; k < result.bcc.length; k++) {
|
||||
//result.bcc[k] = result.bcc[k].replace(/'/g, "\\'");
|
||||
if (result.bcc[k].length > 0 && result.bcc[k].search(/^0x/) !== 0) {
|
||||
result.bcc[k] = "<" + result.bcc[k] + ">";
|
||||
let aliasKeyList = EnigmailKeyRing.getAliasKeyList(email);
|
||||
if (aliasKeyList) {
|
||||
let aliasKeys = EnigmailKeyRing.getAliasKeys(email, aliasKeyList);
|
||||
if (!aliasKeys.length) {
|
||||
errorMsgObj.value = "bad alias definition for " + email;
|
||||
return null;
|
||||
}
|
||||
|
||||
// We insert the definition even if aliasKeys is empty,
|
||||
// because having an alias means we want to skip the usual
|
||||
// lookup - and having the entry tells RNP to skip.
|
||||
result.aliasKeys.set(email, aliasKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (detachedSig) {
|
||||
|
@ -198,7 +218,7 @@ var EnigmailEncryption = {
|
|||
let sign = !!(sendFlags & EnigmailConstants.SEND_SIGNED);
|
||||
let encrypt = !!(sendFlags & EnigmailConstants.SEND_ENCRYPTED);
|
||||
|
||||
if (fromKeyId.search(/^(0x)?[A-Z0-9]+$/) === 0) {
|
||||
if (/^(0x)?[0-9a-f]+$/i.test(fromKeyId)) {
|
||||
// key ID specified
|
||||
foundKey = EnigmailKeyRing.getKeyById(fromKeyId);
|
||||
}
|
||||
|
@ -248,6 +268,7 @@ var EnigmailEncryption = {
|
|||
return ret;
|
||||
},
|
||||
|
||||
// return 0 on success, non-zero on failure
|
||||
encryptMessageStart(
|
||||
win,
|
||||
uiFlags,
|
||||
|
@ -316,7 +337,7 @@ var EnigmailEncryption = {
|
|||
);
|
||||
|
||||
if (!encryptArgs) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!listener) {
|
||||
|
|
|
@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
OpenPGPAlias: "chrome://openpgp/content/modules/OpenPGPAlias.jsm",
|
||||
EnigmailArmor: "chrome://openpgp/content/modules/armor.jsm",
|
||||
EnigmailCryptoAPI: "chrome://openpgp/content/modules/cryptoAPI.jsm",
|
||||
EnigmailFiles: "chrome://openpgp/content/modules/files.jsm",
|
||||
|
@ -979,15 +980,43 @@ var EnigmailKeyRing = {
|
|||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
isValidForEncryption(keyObj) {
|
||||
return this._getValidityLevelIgnoringAcceptance(keyObj, null) == 0;
|
||||
},
|
||||
|
||||
// returns an acceptanceLevel from -1 to 3,
|
||||
// or -2 for "doesn't match email" or "not usable"
|
||||
async isValidKeyForRecipient(keyObj, emailAddr) {
|
||||
if (!emailAddr) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
let level = this._getValidityLevelIgnoringAcceptance(keyObj, emailAddr);
|
||||
if (level < 0) {
|
||||
return level;
|
||||
}
|
||||
return this._getAcceptanceLevelForEmail(keyObj, emailAddr);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function checks that given key is not expired, not revoked,
|
||||
* and that a (related) encryption (sub-)key is available.
|
||||
* If an email address is provided by the caller, the function
|
||||
* also requires that a matching user id is available.
|
||||
*
|
||||
* @param {Object} keyObj - the key to check
|
||||
* @param {String} [emailAddr] - optional email address
|
||||
* @return {Integer} - validity level, negative for invalid,
|
||||
* 0 if no problem were found (neutral)
|
||||
*/
|
||||
_getValidityLevelIgnoringAcceptance(keyObj, emailAddr) {
|
||||
switch (keyObj.keyTrust) {
|
||||
case "e":
|
||||
case "r":
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (emailAddr) {
|
||||
let uidMatch = false;
|
||||
for (let uid of keyObj.userIds) {
|
||||
if (uid.type !== "uid") {
|
||||
|
@ -1005,6 +1034,8 @@ var EnigmailKeyRing = {
|
|||
if (!uidMatch) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
// key valid for encryption?
|
||||
if (!keyObj.keyUseFor.includes("E")) {
|
||||
return -2;
|
||||
|
@ -1033,6 +1064,10 @@ var EnigmailKeyRing = {
|
|||
return -2;
|
||||
}
|
||||
|
||||
return 0; // no problem found
|
||||
},
|
||||
|
||||
async _getAcceptanceLevelForEmail(keyObj, emailAddr) {
|
||||
let acceptanceLevel;
|
||||
if (keyObj.secretAvailable) {
|
||||
let isPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(keyObj.fpr);
|
||||
|
@ -1138,6 +1173,12 @@ var EnigmailKeyRing = {
|
|||
},
|
||||
|
||||
async getKeyAcceptanceLevelForEmail(keyObj, email) {
|
||||
if (keyObj.secretAvailable) {
|
||||
throw new Error(
|
||||
`Unexpected private key parameter; keyObj.fpr=${keyObj.fpr}`
|
||||
);
|
||||
}
|
||||
|
||||
let acceptanceLevel = 0;
|
||||
|
||||
let acceptanceResult = {};
|
||||
|
@ -1200,12 +1241,10 @@ var EnigmailKeyRing = {
|
|||
* * addr {String}: email addresses
|
||||
* * msg {String}: related error
|
||||
* }
|
||||
* - keyMap {Object<String>}: map of email addr -> keyID
|
||||
* @param {Array<String>} resultingArray: list of found key IDs
|
||||
*
|
||||
* @return {Boolean}: true if at least one key missing; false otherwise
|
||||
*/
|
||||
async getValidKeysForAllRecipients(addresses, details, resultingArray) {
|
||||
async getValidKeysForAllRecipients(addresses, details) {
|
||||
if (!addresses) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1213,7 +1252,6 @@ var EnigmailKeyRing = {
|
|||
let keyMissing = false;
|
||||
if (details) {
|
||||
details.errArray = [];
|
||||
details.keyMap = {};
|
||||
}
|
||||
for (let i = 0; i < addresses.length; i++) {
|
||||
let addr = addresses[i];
|
||||
|
@ -1221,7 +1259,6 @@ var EnigmailKeyRing = {
|
|||
continue;
|
||||
}
|
||||
// try to find current address in key list:
|
||||
let keyId = null;
|
||||
var errMsg = null;
|
||||
if (!addr.includes("@")) {
|
||||
throw new Error(
|
||||
|
@ -1230,19 +1267,62 @@ var EnigmailKeyRing = {
|
|||
);
|
||||
}
|
||||
|
||||
let aliasKeyList = this.getAliasKeyList(addr);
|
||||
if (aliasKeyList) {
|
||||
for (let entry of aliasKeyList) {
|
||||
let foundError = true;
|
||||
|
||||
let key;
|
||||
if ("fingerprint" in entry) {
|
||||
key = this.getKeyById(entry.fingerprint);
|
||||
} else if ("id" in entry) {
|
||||
key = this.getKeyById(entry.id);
|
||||
}
|
||||
if (key && this.isValidForEncryption(key)) {
|
||||
let acceptanceResult = {};
|
||||
await PgpSqliteDb2.getFingerprintAcceptance(
|
||||
null,
|
||||
key.fpr,
|
||||
acceptanceResult
|
||||
);
|
||||
// If we don't have acceptance info for the key yet,
|
||||
// or, we have it and it isn't rejected,
|
||||
// then we accept the key for using it in alias definitions.
|
||||
if (
|
||||
!("fingerprintAcceptance" in acceptanceResult) ||
|
||||
acceptanceResult.fingerprintAcceptance != "rejected"
|
||||
) {
|
||||
foundError = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundError) {
|
||||
keyMissing = true;
|
||||
if (details) {
|
||||
let detEl = {};
|
||||
detEl.addr = addr;
|
||||
detEl.msg = "alias problem";
|
||||
details.errArray.push(detEl);
|
||||
}
|
||||
console.debug(
|
||||
'keyRing.jsm: getValidKeysForAllRecipients(): alias key list for="' +
|
||||
addr +
|
||||
' refers to missing or unusable key"\n'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// skip the lookup for direct matching keys by email
|
||||
continue;
|
||||
}
|
||||
|
||||
// try email match:
|
||||
var addrErrDetails = {};
|
||||
let foundKeyId = await this.getValidKeyForRecipient(addr, addrErrDetails);
|
||||
if (details && addrErrDetails.msg) {
|
||||
errMsg = addrErrDetails.msg;
|
||||
}
|
||||
if (foundKeyId) {
|
||||
keyId = "0x" + foundKeyId.toUpperCase();
|
||||
resultingArray.push(keyId);
|
||||
if (details) {
|
||||
details.keyMap[addr.toLowerCase()] = keyId;
|
||||
}
|
||||
} else {
|
||||
if (!foundKeyId) {
|
||||
// no key for this address found
|
||||
keyMissing = true;
|
||||
if (details) {
|
||||
|
@ -1255,9 +1335,9 @@ var EnigmailKeyRing = {
|
|||
details.errArray.push(detailsElem);
|
||||
}
|
||||
EnigmailLog.DEBUG(
|
||||
'keyRing.jsm: getValidKeysForAllRecipients(): return null (no single valid key found for="' +
|
||||
'keyRing.jsm: getValidKeysForAllRecipients(): no single valid key found for="' +
|
||||
addr +
|
||||
'")\n'
|
||||
'"\n'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1299,35 +1379,59 @@ var EnigmailKeyRing = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Determine the key ID for a set of given addresses
|
||||
* If the given email address has an alias definition, return its
|
||||
* list of key identifiers.
|
||||
*
|
||||
* @param {string[]} addresses - Email addresses to get key id for.
|
||||
* The function will prefer a match to an exact email alias.
|
||||
* If no email alias could be found, the function will search for
|
||||
* an alias rule that matches the domain.
|
||||
*
|
||||
* @return {Map<string,keyObj[]>}: map of email addr -> keyObj[]
|
||||
* @param {string} email - The email address to look up
|
||||
* @return {[]} - An array with alias key identifiers found for the
|
||||
* input, or null if no alias matches the address.
|
||||
*/
|
||||
async getMultValidKeysForMultRecipients(addresses) {
|
||||
if (!addresses) {
|
||||
return null;
|
||||
}
|
||||
let allKeysMap = new Map();
|
||||
for (let i = 0; i < addresses.length; i++) {
|
||||
let addr = addresses[i].toLowerCase();
|
||||
if (!addr) {
|
||||
continue;
|
||||
getAliasKeyList(email) {
|
||||
let ekl = OpenPGPAlias.getEmailAliasKeyList(email);
|
||||
if (ekl) {
|
||||
return ekl;
|
||||
}
|
||||
|
||||
if (!addr.includes("@")) {
|
||||
throw new Error(
|
||||
"getAllRecipientKeys unexpected lookup for non-email addr: " + addr
|
||||
return OpenPGPAlias.getDomainAliasKeyList(email);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the fingerprint of each usable alias key for the given
|
||||
* email address.
|
||||
*
|
||||
* @param {string} email - The email address to look up.
|
||||
* @param {String[]} keyList - Array of key identifiers
|
||||
* @return {String[]} An array with fingerprints of each usable alias key.
|
||||
*/
|
||||
getAliasKeys(email, keyList) {
|
||||
let keys = [];
|
||||
|
||||
for (let entry of keyList) {
|
||||
let key;
|
||||
let lookupId;
|
||||
if ("fingerprint" in entry) {
|
||||
lookupId = entry.fingerprint;
|
||||
key = this.getKeyById(entry.fingerprint);
|
||||
} else if ("id" in entry) {
|
||||
lookupId = entry.id;
|
||||
key = this.getKeyById(entry.id);
|
||||
}
|
||||
if (key && this.isValidForEncryption(key)) {
|
||||
keys.push(key.fpr);
|
||||
} else {
|
||||
let reason = key ? "not usable" : "missing";
|
||||
console.debug(
|
||||
"getAliasKeys: key for identifier: " + lookupId + " is " + reason
|
||||
);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
let found = await this.getMultValidKeysForOneRecipient(addr);
|
||||
if (found) {
|
||||
allKeysMap.set(addr, found);
|
||||
}
|
||||
}
|
||||
return allKeysMap;
|
||||
return keys;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,6 +65,13 @@ var PgpSqliteDb2 = {
|
|||
accCacheEmails: null,
|
||||
|
||||
async getFingerprintAcceptance(conn, fingerprint, rv) {
|
||||
// 40 is for modern fingerprints, 32 for older fingerprints.
|
||||
if (fingerprint.length != 40 && fingerprint.length != 32) {
|
||||
throw new Error(
|
||||
"internal error, invalid fingerprint value: " + fingerprint
|
||||
);
|
||||
}
|
||||
|
||||
fingerprint = fingerprint.toLowerCase();
|
||||
if (fingerprint == this.accCacheFingerprint) {
|
||||
rv.fingerprintAcceptance = this.accCacheValue;
|
||||
|
|
|
@ -15,15 +15,24 @@ var { EnigmailWindows } = ChromeUtils.import(
|
|||
var { EnigmailKey } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/key.jsm"
|
||||
);
|
||||
const { OpenPGPAlias } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/OpenPGPAlias.jsm"
|
||||
);
|
||||
const { PgpSqliteDb2 } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/sqliteDb.jsm"
|
||||
);
|
||||
|
||||
var gListBox;
|
||||
var gViewButton;
|
||||
var gLdapBundle;
|
||||
|
||||
var gEmailAddresses = [];
|
||||
var gRowToEmail = [];
|
||||
|
||||
// One boolean entry per row. True means it is an alias row.
|
||||
// This allows us to use different dialog behavior for alias entries.
|
||||
var gAliasRows = [];
|
||||
|
||||
var gMapAddressToKeyObjs = null;
|
||||
|
||||
function addRecipients(toAddrList, recList) {
|
||||
|
@ -38,37 +47,53 @@ function addRecipients(toAddrList, recList) {
|
|||
}
|
||||
|
||||
async function setListEntries() {
|
||||
gMapAddressToKeyObjs = await EnigmailKeyRing.getMultValidKeysForMultRecipients(
|
||||
gEmailAddresses
|
||||
);
|
||||
if (!gMapAddressToKeyObjs) {
|
||||
throw new Error("getMultValidKeysForMultRecipients failed");
|
||||
}
|
||||
gMapAddressToKeyObjs = new Map();
|
||||
|
||||
for (let addr of gEmailAddresses) {
|
||||
let emailStatus = null;
|
||||
|
||||
addr = addr.toLowerCase();
|
||||
let foundKeys = gMapAddressToKeyObjs.get(addr);
|
||||
if (!foundKeys || !foundKeys.length) {
|
||||
emailStatus = "openpgp-recip-missing";
|
||||
|
||||
let statusStringID = null;
|
||||
let statusStringDirect = "";
|
||||
|
||||
let aliasKeyList = EnigmailKeyRing.getAliasKeyList(addr);
|
||||
let isAlias = !!aliasKeyList;
|
||||
|
||||
if (isAlias) {
|
||||
let aliasKeys = EnigmailKeyRing.getAliasKeys(addr, aliasKeyList);
|
||||
if (!aliasKeys.length) {
|
||||
// failure, at least one alias key is unusable/unavailable
|
||||
statusStringDirect = gLdapBundle.getString("33");
|
||||
} else {
|
||||
// use a better string after 78, bug 1679301
|
||||
statusStringDirect = "a -> b";
|
||||
}
|
||||
} else {
|
||||
let foundKeys = await EnigmailKeyRing.getMultValidKeysForOneRecipient(
|
||||
addr
|
||||
);
|
||||
if (!foundKeys || !foundKeys.length) {
|
||||
statusStringID = "openpgp-recip-missing";
|
||||
} else {
|
||||
gMapAddressToKeyObjs.set(addr, foundKeys);
|
||||
for (let keyObj of foundKeys) {
|
||||
let goodPersonal = false;
|
||||
if (keyObj.secretAvailable) {
|
||||
goodPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(keyObj.fpr);
|
||||
goodPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(
|
||||
keyObj.fpr
|
||||
);
|
||||
}
|
||||
if (
|
||||
goodPersonal ||
|
||||
keyObj.acceptance == "verified" ||
|
||||
keyObj.acceptance == "unverified"
|
||||
) {
|
||||
emailStatus = "openpgp-recip-good";
|
||||
statusStringID = "openpgp-recip-good";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!emailStatus) {
|
||||
emailStatus = "openpgp-recip-none-accepted";
|
||||
if (!statusStringID) {
|
||||
statusStringID = "openpgp-recip-none-accepted";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +106,13 @@ async function setListEntries() {
|
|||
listitem.appendChild(emailItem);
|
||||
|
||||
let status = document.createXULElement("label");
|
||||
document.l10n.setAttributes(status, emailStatus);
|
||||
|
||||
if (statusStringID) {
|
||||
document.l10n.setAttributes(status, statusStringID);
|
||||
} else {
|
||||
status.setAttribute("value", statusStringDirect);
|
||||
}
|
||||
|
||||
status.setAttribute("crop", "end");
|
||||
status.setAttribute("style", "width: var(--statusWidth)");
|
||||
listitem.appendChild(status);
|
||||
|
@ -89,6 +120,7 @@ async function setListEntries() {
|
|||
gListBox.appendChild(listitem);
|
||||
|
||||
gRowToEmail.push(addr);
|
||||
gAliasRows.push(isAlias);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,9 +130,14 @@ async function onLoad() {
|
|||
return;
|
||||
}
|
||||
|
||||
await OpenPGPAlias.load();
|
||||
|
||||
gListBox = document.getElementById("infolist");
|
||||
gViewButton = document.getElementById("detailsButton");
|
||||
|
||||
// Fix as part of bug 1679301
|
||||
gLdapBundle = document.getElementById("bundle_ldap");
|
||||
|
||||
var arrLen = {};
|
||||
var recList;
|
||||
|
||||
|
@ -147,7 +184,10 @@ async function reloadAndReselect(selIndex = -1) {
|
|||
}
|
||||
|
||||
function onSelectionChange(event) {
|
||||
gViewButton.disabled = !gListBox.selectedItems.length;
|
||||
// We don't offer detail management/discovery for email addresses
|
||||
// that match an alias rule.
|
||||
gViewButton.disabled =
|
||||
!gListBox.selectedItems.length || gAliasRows[gListBox.selectedIndex];
|
||||
}
|
||||
|
||||
function viewSelectedEmail() {
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
]]></script>
|
||||
<script src="chrome://messenger/content/dialogShadowDom.js"/>
|
||||
|
||||
<!-- TODO: Remove after 78 is done, bug 1679301 -->
|
||||
<stringbundle id="bundle_ldap" src="chrome://mozldap/locale/ldap.properties"/>
|
||||
|
||||
<linkset>
|
||||
<html:link rel="localization" href="messenger/openpgp/composeKeyStatus.ftl"/>
|
||||
</linkset>
|
||||
|
|
|
@ -46,43 +46,15 @@ if (!Enigmail) {
|
|||
}
|
||||
|
||||
Enigmail.hlp = {
|
||||
/* try to find valid key to passed email addresses (or keys)
|
||||
* @return: list of all found key (with leading "0x") or null
|
||||
* details in details parameter
|
||||
/**
|
||||
* Check availability of valid keys for passed email addresses (or keys).
|
||||
* @param {String} emailsOrKeys - comma separated list
|
||||
* @param {Object} details - holds details for invalid keys, see
|
||||
* EnigmailKeyRing.getValidKeysForAllRecipients
|
||||
* @return {Boolean} - false on failure
|
||||
*/
|
||||
async validKeysForAllRecipients(emailsOrKeys, details) {
|
||||
EnigmailLog.DEBUG("=====> validKeysForAllRecipients()\n");
|
||||
EnigmailLog.DEBUG(
|
||||
"enigmailMsgComposeHelper.js: validKeysForAllRecipients(): emailsOrKeys='" +
|
||||
emailsOrKeys +
|
||||
"'\n"
|
||||
);
|
||||
|
||||
// use helper to see when we enter and leave this function
|
||||
let resultingArray = await this.doValidKeysForAllRecipients(
|
||||
emailsOrKeys,
|
||||
details
|
||||
);
|
||||
|
||||
EnigmailLog.DEBUG(
|
||||
"enigmailMsgComposeHelper.js: validKeysForAllRecipients(): return '" +
|
||||
resultingArray +
|
||||
"'\n"
|
||||
);
|
||||
EnigmailLog.DEBUG(" <=== validKeysForAllRecipients()\n");
|
||||
return resultingArray;
|
||||
},
|
||||
|
||||
// helper for validKeysForAllRecipients()
|
||||
async doValidKeysForAllRecipients(emailsOrKeys, details) {
|
||||
EnigmailLog.DEBUG(
|
||||
"enigmailMsgComposeHelper.js: doValidKeysForAllRecipients(): emailsOrKeys='" +
|
||||
emailsOrKeys +
|
||||
"'\n"
|
||||
);
|
||||
|
||||
let keyMissing;
|
||||
let resultingArray = []; // resulting key list (if all valid)
|
||||
let keyMissing = true;
|
||||
try {
|
||||
// create array of address elements (email or key)
|
||||
let addresses = [];
|
||||
|
@ -93,30 +65,22 @@ Enigmail.hlp = {
|
|||
// resolve all the email addresses if possible:
|
||||
keyMissing = await EnigmailKeyRing.getValidKeysForAllRecipients(
|
||||
addresses,
|
||||
details,
|
||||
resultingArray
|
||||
details
|
||||
);
|
||||
} catch (ex) {
|
||||
EnigmailLog.DEBUG(
|
||||
"enigmailMsgComposeHelper.js: doValidKeysForAllRecipients(): return null (exception: " +
|
||||
"enigmailMsgComposeHelper.js: validKeysForAllRecipients(): return null (exception: " +
|
||||
ex.message +
|
||||
"\n" +
|
||||
ex.stack +
|
||||
")\n"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
if (keyMissing) {
|
||||
EnigmailLog.DEBUG(
|
||||
"enigmailMsgComposeHelper.js: doValidKeysForAllRecipients(): return null (key missing)\n"
|
||||
"enigmailMsgComposeHelper.js: validKeysForAllRecipients(): return null (key missing)\n"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
EnigmailLog.DEBUG(
|
||||
'enigmailMsgComposeHelper.js: doValidKeysForAllRecipients(): return "' +
|
||||
resultingArray +
|
||||
'"\n'
|
||||
);
|
||||
return resultingArray;
|
||||
return !keyMissing;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -96,6 +96,9 @@ var EnigmailMimeEncrypt = ChromeUtils.import(
|
|||
const { EnigmailCryptoAPI } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/cryptoAPI.jsm"
|
||||
);
|
||||
const { OpenPGPAlias } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/OpenPGPAlias.jsm"
|
||||
);
|
||||
var { jsmime } = ChromeUtils.import("resource:///modules/jsmime.jsm");
|
||||
|
||||
var l10nOpenPGP = new Localization(["messenger/openpgp/openpgp.ftl"]);
|
||||
|
@ -1240,6 +1243,8 @@ Enigmail.msg = {
|
|||
// gMsgCompose.expandMailingLists();
|
||||
|
||||
if (Enigmail.msg.isEnigmailEnabledForIdentity()) {
|
||||
await OpenPGPAlias.load();
|
||||
|
||||
var toAddrList = [];
|
||||
var arrLen = {};
|
||||
var recList;
|
||||
|
|
|
@ -54,7 +54,7 @@ async function setListEntries(keys = null) {
|
|||
} else {
|
||||
if (!("acceptance" in keyObj)) {
|
||||
throw new Error(
|
||||
"expected getMultValidKeysForMultRecipients to set acceptance"
|
||||
"expected getMultValidKeysForOneRecipient to set acceptance"
|
||||
);
|
||||
}
|
||||
switch (keyObj.acceptance) {
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Tests for OpenPGP encryption alias rules.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { RNP } = ChromeUtils.import("chrome://openpgp/content/modules/RNP.jsm");
|
||||
const { EnigmailConstants } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/constants.jsm"
|
||||
);
|
||||
const { EnigmailKeyRing } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/keyRing.jsm"
|
||||
);
|
||||
const { EnigmailEncryption } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/encryption.jsm"
|
||||
);
|
||||
const { OpenPGPAlias } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/OpenPGPAlias.jsm"
|
||||
);
|
||||
|
||||
const { OpenPGPTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/mozmill/OpenPGPTestUtils.jsm"
|
||||
);
|
||||
|
||||
const keyDir = "../../../../../test/browser/openpgp/data/keys";
|
||||
const mailNewsDir = "../../../../../../mailnews/test/data";
|
||||
|
||||
// Alice's key: EB85BB5FA33A75E15E944E63F231550C4F47E38E
|
||||
// Bob's key: D1A66E1A23B182C9980F788CFBFCC82A015E7330
|
||||
// Carol's key: B8F2F6F4BD3AD3F82DC446833099FF1238852B9F
|
||||
|
||||
const tests = [
|
||||
{
|
||||
info: "Should find Alice's key directly",
|
||||
filename: undefined,
|
||||
to: "alice@openpgp.example",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: null,
|
||||
},
|
||||
{
|
||||
info: "Key absent, no alias defined for address",
|
||||
filename: `${mailNewsDir}/alias-1.json`,
|
||||
to: "nobody@openpgp.example",
|
||||
expectedMissing: true,
|
||||
expectedAliasKeys: null,
|
||||
},
|
||||
{
|
||||
info:
|
||||
"File maps Alice's address to Bob's (id) and Carol's (fingerprint) keys",
|
||||
filename: `${mailNewsDir}/alias-1.json`,
|
||||
to: "alice@openpgp.example",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: [
|
||||
"D1A66E1A23B182C9980F788CFBFCC82A015E7330",
|
||||
"B8F2F6F4BD3AD3F82DC446833099FF1238852B9F",
|
||||
],
|
||||
},
|
||||
{
|
||||
info: "File maps Alice's address to an absent key",
|
||||
filename: `${mailNewsDir}/alias-2.json`,
|
||||
to: "alice@openpgp.example",
|
||||
expectedMissing: true,
|
||||
expectedAliasKeys: null,
|
||||
},
|
||||
{
|
||||
info: "File maps Alice's address to Alice's key (unnecessary alias)",
|
||||
filename: `${mailNewsDir}/alias-3.json`,
|
||||
to: "alice@openpgp.example",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: ["EB85BB5FA33A75E15E944E63F231550C4F47E38E"],
|
||||
},
|
||||
{
|
||||
info: "File maps an address to several keys, all available",
|
||||
filename: `${mailNewsDir}/alias-4.json`,
|
||||
to: "nobody@example.com",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: [
|
||||
"EB85BB5FA33A75E15E944E63F231550C4F47E38E",
|
||||
"D1A66E1A23B182C9980F788CFBFCC82A015E7330",
|
||||
"B8F2F6F4BD3AD3F82DC446833099FF1238852B9F",
|
||||
],
|
||||
},
|
||||
{
|
||||
info: "File maps an address to several keys, one not available",
|
||||
filename: `${mailNewsDir}/alias-5.json`,
|
||||
to: "nobody@example.com",
|
||||
expectedMissing: true,
|
||||
expectedAliasKeys: null,
|
||||
},
|
||||
{
|
||||
info: "File maps the domain to Carol's key",
|
||||
filename: `${mailNewsDir}/alias-6.json`,
|
||||
to: "someone@example.com",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: ["B8F2F6F4BD3AD3F82DC446833099FF1238852B9F"],
|
||||
},
|
||||
{
|
||||
info: "Multiple rules, should match domain1 rule",
|
||||
filename: `${mailNewsDir}/alias-7.json`,
|
||||
to: "someone@domain1.example.com",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: ["EB85BB5FA33A75E15E944E63F231550C4F47E38E"],
|
||||
},
|
||||
{
|
||||
info: "Multiple rules, should match domain2 rule",
|
||||
filename: `${mailNewsDir}/alias-7.json`,
|
||||
to: "contact@domain2.example.com",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: ["D1A66E1A23B182C9980F788CFBFCC82A015E7330"],
|
||||
},
|
||||
{
|
||||
info: "Multiple rules, should match email contact@domain1 rule",
|
||||
filename: `${mailNewsDir}/alias-7.json`,
|
||||
to: "contact@domain1.example.com",
|
||||
expectedMissing: false,
|
||||
expectedAliasKeys: [
|
||||
"D1A66E1A23B182C9980F788CFBFCC82A015E7330",
|
||||
"EB85BB5FA33A75E15E944E63F231550C4F47E38E",
|
||||
],
|
||||
},
|
||||
{
|
||||
info: "Multiple rules, shouldn't match",
|
||||
filename: `${mailNewsDir}/alias-7.json`,
|
||||
to: "contact@domain2.example",
|
||||
expectedMissing: true,
|
||||
expectedAliasKeys: null,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Initialize OpenPGP add testing keys.
|
||||
*/
|
||||
add_task(async function setUp() {
|
||||
do_get_profile();
|
||||
|
||||
await OpenPGPTestUtils.initOpenPGP();
|
||||
|
||||
await OpenPGPTestUtils.importPublicKey(
|
||||
null,
|
||||
do_get_file(`${keyDir}/alice@openpgp.example-0xf231550c4f47e38e-pub.asc`)
|
||||
);
|
||||
|
||||
await OpenPGPTestUtils.importPublicKey(
|
||||
null,
|
||||
do_get_file(`${keyDir}/bob@openpgp.example-0xfbfcc82a015e7330-pub.asc`)
|
||||
);
|
||||
|
||||
await OpenPGPTestUtils.importPublicKey(
|
||||
null,
|
||||
do_get_file(`${keyDir}/carol@example.com-0x3099ff1238852b9f-pub.asc`)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function testAlias() {
|
||||
let aliasFilename = "openpgp-alias-rules.json";
|
||||
let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
for (let test of tests) {
|
||||
if (test.filename) {
|
||||
info(`Running alias test with rules from: ${test.filename}`);
|
||||
|
||||
// Copy test file to profile directory (which is a relative path),
|
||||
// because load function only works with simple filenames
|
||||
// or absolute file URLs.
|
||||
|
||||
let inFile = do_get_file(test.filename);
|
||||
inFile.copyTo(profileDir, aliasFilename);
|
||||
|
||||
await OpenPGPAlias._loadFromFile(aliasFilename);
|
||||
} else {
|
||||
info(`Running alias test without rules`);
|
||||
OpenPGPAlias._clear();
|
||||
}
|
||||
info(test.info);
|
||||
|
||||
let addresses = [test.to];
|
||||
let resultDetails = {};
|
||||
|
||||
let isMissing = await EnigmailKeyRing.getValidKeysForAllRecipients(
|
||||
addresses,
|
||||
resultDetails
|
||||
);
|
||||
|
||||
Assert.ok(
|
||||
(isMissing && test.expectedMissing) ||
|
||||
(!isMissing && !test.expectedMissing),
|
||||
"Should have the expected result from getValidKeysForAllRecipients"
|
||||
);
|
||||
|
||||
if (isMissing || test.expectedMissing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let errorMsgObj = { value: "" };
|
||||
let logFileObj = {};
|
||||
let encryptArgs = EnigmailEncryption.getCryptParams(
|
||||
"",
|
||||
test.to,
|
||||
"",
|
||||
"SHA256",
|
||||
EnigmailConstants.SEND_ENCRYPTED,
|
||||
0,
|
||||
errorMsgObj,
|
||||
logFileObj
|
||||
);
|
||||
|
||||
let foundAliasKeys = encryptArgs.aliasKeys.get(test.to);
|
||||
|
||||
if (!test.expectedAliasKeys) {
|
||||
Assert.ok(!foundAliasKeys, "foundAliasKeys should be empty");
|
||||
} else {
|
||||
Assert.equal(foundAliasKeys.length, test.expectedAliasKeys.length);
|
||||
|
||||
test.expectedAliasKeys.forEach((val, i) => {
|
||||
Assert.ok(foundAliasKeys.includes(val));
|
||||
});
|
||||
|
||||
let encryptResult = {};
|
||||
let encrypted = await RNP.encryptAndOrSign(
|
||||
"plaintext",
|
||||
encryptArgs,
|
||||
encryptResult
|
||||
);
|
||||
|
||||
Assert.ok(
|
||||
!encryptResult.exitCode,
|
||||
"RNP.encryptAndOrSign() should exit ok"
|
||||
);
|
||||
|
||||
Assert.ok(encrypted.includes("END PGP MESSAGE"));
|
||||
}
|
||||
}
|
||||
});
|
|
@ -200,6 +200,7 @@ add_task(async function testEncryptAndOrSignResults() {
|
|||
let encryptResult = {};
|
||||
|
||||
let encryptArgs = {
|
||||
aliasKeys: new Map(),
|
||||
armor: true,
|
||||
bcc: [],
|
||||
encrypt: true,
|
||||
|
|
|
@ -8,3 +8,4 @@ support-files =
|
|||
|
||||
[test_encryptAndOrSign.js]
|
||||
[test_secretKeys.js]
|
||||
[test_alias.js]
|
||||
|
|
|
@ -19,6 +19,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
OpenPGPAlias: "chrome://openpgp/content/modules/OpenPGPAlias.jsm",
|
||||
EnigmailCore: "chrome://openpgp/content/modules/core.jsm",
|
||||
EnigmailKeyRing: "chrome://openpgp/content/modules/keyRing.jsm",
|
||||
EnigmailFiles: "chrome://openpgp/content/modules/files.jsm",
|
||||
|
@ -69,6 +70,7 @@ const OpenPGPTestUtils = {
|
|||
Assert.ok(await RNP.init(), "librnp did load");
|
||||
Assert.ok(await EnigmailCore.getService({}), "EnigmailCore did load");
|
||||
EnigmailKeyRing.init();
|
||||
await OpenPGPAlias.load();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"email": "alice@openpgp.example",
|
||||
"keys": [
|
||||
{ "id": "FBFCC82A015E7330" },
|
||||
{ "fingerprint": "B8F2F6F4BD3AD3F82DC446833099FF1238852B9F" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"email": "alice@openpgp.example",
|
||||
"keys": [
|
||||
{ "fingerprint": "0123456789012345678901234567890123456789" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"email": "alice@openpgp.example",
|
||||
"keys": [
|
||||
{ "fingerprint": "EB85BB5FA33A75E15E944E63F231550C4F47E38E" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"email": "nobody@example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "EB85BB5FA33A75E15E944E63F231550C4F47E38E" },
|
||||
{ "fingerprint": "D1A66E1A23B182C9980F788CFBFCC82A015E7330" },
|
||||
{ "fingerprint": "B8F2F6F4BD3AD3F82DC446833099FF1238852B9F" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"email": "nobody@example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "EB85BB5FA33A75E15E944E63F231550C4F47E38E" },
|
||||
{ "fingerprint": "D1A66E1A23B182C9980F788CFBFCC82A015E7330" },
|
||||
{ "fingerprint": "B8F2F6F4BD3AD3F82DC446833099FF1238852B9F" },
|
||||
{ "fingerprint": "0123456789012345678901234567890123456789" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"domain": "example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "B8F2F6F4BD3AD3F82DC446833099FF1238852B9F" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"description": "OpenPGP alias rules",
|
||||
"rules": [
|
||||
{
|
||||
"domain": "domain1.example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "EB85BB5FA33A75E15E944E63F231550C4F47E38E" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"domain": "domain2.example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "D1A66E1A23B182C9980F788CFBFCC82A015E7330" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"email": "contact@domain1.example.com",
|
||||
"keys": [
|
||||
{ "fingerprint": "D1A66E1A23B182C9980F788CFBFCC82A015E7330" },
|
||||
{ "id": "F231550C4F47E38E" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Загрузка…
Ссылка в новой задаче