Merge pull request #693 from twiss/userid
Parse user IDs & allow selecting user when encrypting/signing
This commit is contained in:
commit
4c9d025193
|
@ -29,8 +29,8 @@ module.exports = function(grunt) {
|
|||
transform: [
|
||||
["babelify", {
|
||||
global: true,
|
||||
// Only babelify asmcrypto in node_modules
|
||||
only: /^(?:.*\/node_modules\/asmcrypto\.js\/|(?!.*\/node_modules\/)).*$/,
|
||||
// Only babelify asmcrypto and address-rfc2822 in node_modules
|
||||
only: /^(?:.*\/node_modules\/asmcrypto\.js\/|.*\/node_modules\/address-rfc2822\/|(?!.*\/node_modules\/)).*$/,
|
||||
plugins: ["transform-async-to-generator",
|
||||
"syntax-async-functions",
|
||||
"transform-regenerator",
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
"whatwg-fetch": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"address-rfc2822": "^2.0.3",
|
||||
"asmcrypto.js": "^0.22.0",
|
||||
"asn1.js": "^5.0.0",
|
||||
"bn.js": "^4.11.8",
|
||||
|
|
|
@ -70,11 +70,12 @@ CleartextMessage.prototype.getSigningKeyIds = function() {
|
|||
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
|
||||
* @param {Signature} signature (optional) any existing detached signature
|
||||
* @param {Date} date (optional) The creation time of the signature that should be created
|
||||
* @param {Object} userId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<module:cleartext.CleartextMessage>} new cleartext message with signed content
|
||||
* @async
|
||||
*/
|
||||
CleartextMessage.prototype.sign = async function(privateKeys, signature=null, date=new Date()) {
|
||||
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date));
|
||||
CleartextMessage.prototype.sign = async function(privateKeys, signature=null, date=new Date(), userId={}) {
|
||||
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date, userId));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -82,14 +83,15 @@ CleartextMessage.prototype.sign = async function(privateKeys, signature=null, da
|
|||
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
|
||||
* @param {Signature} signature (optional) any existing detached signature
|
||||
* @param {Date} date (optional) The creation time of the signature that should be created
|
||||
* @param {Object} userId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
||||
* @async
|
||||
*/
|
||||
CleartextMessage.prototype.signDetached = async function(privateKeys, signature=null, date=new Date()) {
|
||||
CleartextMessage.prototype.signDetached = async function(privateKeys, signature=null, date=new Date(), userId={}) {
|
||||
const literalDataPacket = new packet.Literal();
|
||||
literalDataPacket.setText(this.text);
|
||||
|
||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date));
|
||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date, userId));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
68
src/key.js
68
src/key.js
|
@ -279,14 +279,15 @@ function isValidSigningKeyPacket(keyPacket, signature, date=new Date()) {
|
|||
* Returns first key packet or key packet by given keyId that is available for signing and verification
|
||||
* @param {module:type/keyid} keyId, optional
|
||||
* @param {Date} date use the given date for verification instead of the current time
|
||||
* @param {Object} userId, optional user ID
|
||||
* @returns {Promise<module:packet.SecretSubkey|
|
||||
* module:packet.SecretKey|null>} key packet or null if no signing key has been found
|
||||
* @async
|
||||
*/
|
||||
Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date()) {
|
||||
Key.prototype.getSigningKeyPacket = async function (keyId=null, date=new Date(), userId={}) {
|
||||
const primaryKey = this.primaryKey;
|
||||
if (await this.verifyPrimaryKey(date) === enums.keyStatus.valid) {
|
||||
const primaryUser = await this.getPrimaryUser(date);
|
||||
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
||||
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||
isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
||||
return primaryKey;
|
||||
|
@ -322,15 +323,16 @@ function isValidEncryptionKeyPacket(keyPacket, signature, date=new Date()) {
|
|||
* Returns first key packet or key packet by given keyId that is available for encryption or decryption
|
||||
* @param {module:type/keyid} keyId, optional
|
||||
* @param {Date} date, optional
|
||||
* @param {String} userId, optional
|
||||
* @returns {Promise<module:packet.PublicSubkey|
|
||||
* module:packet.SecretSubkey|
|
||||
* module:packet.SecretKey|
|
||||
* module:packet.PublicKey|null>} key packet or null if no encryption key has been found
|
||||
* @async
|
||||
*/
|
||||
Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date()) {
|
||||
Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date(), userId={}) {
|
||||
const primaryKey = this.primaryKey;
|
||||
if (await this.verifyPrimaryKey(date) === enums.keyStatus.valid) {
|
||||
if (await this.verifyPrimaryKey(date, userId) === enums.keyStatus.valid) {
|
||||
// V4: by convention subkeys are preferred for encryption service
|
||||
// V3: keys MUST NOT have subkeys
|
||||
for (let i = 0; i < this.subKeys.length; i++) {
|
||||
|
@ -345,7 +347,7 @@ Key.prototype.getEncryptionKeyPacket = async function(keyId, date=new Date()) {
|
|||
}
|
||||
}
|
||||
// if no valid subkey for encryption, evaluate primary key
|
||||
const primaryUser = await this.getPrimaryUser(date);
|
||||
const primaryUser = await this.getPrimaryUser(date, userId);
|
||||
if (primaryUser && (!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
||||
isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification, date)) {
|
||||
return primaryKey;
|
||||
|
@ -433,10 +435,11 @@ Key.prototype.isRevoked = async function(signature, key, date=new Date()) {
|
|||
* Verify primary key. Checks for revocation signatures, expiration time
|
||||
* and valid self signature
|
||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||
* @param {Object} userId (optional) user ID
|
||||
* @returns {Promise<module:enums.keyStatus>} The status of the primary key
|
||||
* @async
|
||||
*/
|
||||
Key.prototype.verifyPrimaryKey = async function(date=new Date()) {
|
||||
Key.prototype.verifyPrimaryKey = async function(date=new Date(), userId={}) {
|
||||
const primaryKey = this.primaryKey;
|
||||
// check for key revocation signatures
|
||||
if (await this.isRevoked(null, null, date)) {
|
||||
|
@ -448,7 +451,7 @@ Key.prototype.verifyPrimaryKey = async function(date=new Date()) {
|
|||
return enums.keyStatus.no_self_cert;
|
||||
}
|
||||
// check for valid, unrevoked, unexpired self signature
|
||||
const { user, selfCertification } = await this.getPrimaryUser(date) || {};
|
||||
const { user, selfCertification } = await this.getPrimaryUser(date, userId) || {};
|
||||
if (!user) {
|
||||
return enums.keyStatus.invalid;
|
||||
}
|
||||
|
@ -482,24 +485,35 @@ Key.prototype.getExpirationTime = async function() {
|
|||
* - if multiple primary users exist, returns the one with the latest self signature
|
||||
* - otherwise, returns the user with the latest self signature
|
||||
* @param {Date} date use the given date for verification instead of the current time
|
||||
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
||||
* @returns {Promise<{user: module:key.User,
|
||||
* selfCertification: module:packet.Signature}>} The primary user and the self signature
|
||||
* @async
|
||||
*/
|
||||
Key.prototype.getPrimaryUser = async function(date=new Date()) {
|
||||
// sort by primary user flag and signature creation time
|
||||
const primaryUser = this.users.map(function(user, index) {
|
||||
Key.prototype.getPrimaryUser = async function(date=new Date(), userId={}) {
|
||||
const users = this.users.map(function(user, index) {
|
||||
const selfCertification = getLatestSignature(user.selfCertifications, date);
|
||||
return { index, user, selfCertification };
|
||||
}).sort(function(a, b) {
|
||||
const A = a.selfCertification;
|
||||
const B = b.selfCertification;
|
||||
return (A.isPrimaryUserID - B.isPrimaryUserID) || (A.created - B.created);
|
||||
}).pop();
|
||||
const { user, selfCertification: cert } = primaryUser;
|
||||
if (!user.userId) {
|
||||
}).filter(({ user }) => {
|
||||
return user.userId && (
|
||||
(userId.name === undefined || user.userId.name === userId.name) &&
|
||||
(userId.email === undefined || user.userId.email === userId.email) &&
|
||||
(userId.comment === undefined || user.userId.comment === userId.comment)
|
||||
);
|
||||
});
|
||||
if (!users.length) {
|
||||
if (userId) {
|
||||
throw new Error('Could not find user that matches that user ID');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// sort by primary user flag and signature creation time
|
||||
const primaryUser = users.sort(function(a, b) {
|
||||
const A = a.selfCertification;
|
||||
const B = b.selfCertification;
|
||||
return A.isPrimaryUserID - B.isPrimaryUserID || A.created - B.created;
|
||||
}).pop();
|
||||
const { user, selfCertification: cert } = primaryUser;
|
||||
const { primaryKey } = this;
|
||||
const dataToVerify = { userid: user.userId , key: primaryKey };
|
||||
// skip if certificates is invalid, revoked, or expired
|
||||
|
@ -1244,7 +1258,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
|
|||
|
||||
await Promise.all(options.userIds.map(async function(userId, index) {
|
||||
const userIdPacket = new packet.Userid();
|
||||
userIdPacket.read(util.str_to_Uint8Array(userId));
|
||||
userIdPacket.format(userId);
|
||||
|
||||
const dataToSign = {};
|
||||
dataToSign.userid = userIdPacket;
|
||||
|
@ -1403,21 +1417,22 @@ function getExpirationTime(keyPacket, signature) {
|
|||
* Returns the preferred signature hash algorithm of a key
|
||||
* @param {object} key
|
||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||
* @param {Object} userId (optional) user ID
|
||||
* @returns {Promise<String>}
|
||||
* @async
|
||||
*/
|
||||
export async function getPreferredHashAlgo(key, date) {
|
||||
export async function getPreferredHashAlgo(key, date=new Date(), userId={}) {
|
||||
let hash_algo = config.prefer_hash_algorithm;
|
||||
let pref_algo = hash_algo;
|
||||
if (key instanceof Key) {
|
||||
const primaryUser = await key.getPrimaryUser(date);
|
||||
const primaryUser = await key.getPrimaryUser(date, userId);
|
||||
if (primaryUser && primaryUser.selfCertification.preferredHashAlgorithms) {
|
||||
[pref_algo] = primaryUser.selfCertification.preferredHashAlgorithms;
|
||||
hash_algo = crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
|
||||
pref_algo : hash_algo;
|
||||
}
|
||||
// disable expiration checks
|
||||
key = key.getSigningKeyPacket(undefined, null);
|
||||
key = key.getSigningKeyPacket(undefined, null, userId);
|
||||
}
|
||||
switch (Object.getPrototypeOf(key)) {
|
||||
case packet.SecretKey.prototype:
|
||||
|
@ -1440,15 +1455,16 @@ export async function getPreferredHashAlgo(key, date) {
|
|||
* @param {symmetric|aead} type Type of preference to return
|
||||
* @param {Array<module:key.Key>} keys Set of keys
|
||||
* @param {Date} date (optional) use the given date for verification instead of the current time
|
||||
* @param {Object} userId (optional) user ID
|
||||
* @returns {Promise<module:enums.symmetric>} Preferred symmetric algorithm
|
||||
* @async
|
||||
*/
|
||||
export async function getPreferredAlgo(type, keys, date) {
|
||||
export async function getPreferredAlgo(type, keys, date=new Date(), userId={}) {
|
||||
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
|
||||
const defaultAlgo = type === 'symmetric' ? config.encryption_cipher : config.aead_mode;
|
||||
const prioMap = {};
|
||||
await Promise.all(keys.map(async function(key) {
|
||||
const primaryUser = await key.getPrimaryUser(date);
|
||||
const primaryUser = await key.getPrimaryUser(date, userId);
|
||||
if (!primaryUser || !primaryUser.selfCertification[prefProperty]) {
|
||||
return defaultAlgo;
|
||||
}
|
||||
|
@ -1480,11 +1496,11 @@ export async function getPreferredAlgo(type, keys, date) {
|
|||
* @returns {Promise<Boolean>}
|
||||
* @async
|
||||
*/
|
||||
export async function isAeadSupported(keys, date) {
|
||||
export async function isAeadSupported(keys, date=new Date(), userId={}) {
|
||||
let supported = true;
|
||||
// TODO replace when Promise.some or Promise.any are implemented
|
||||
await Promise.all(keys.map(async function(key) {
|
||||
const primaryUser = await key.getPrimaryUser(date);
|
||||
const primaryUser = await key.getPrimaryUser(date, userId);
|
||||
if (!primaryUser || !primaryUser.selfCertification.features ||
|
||||
!(primaryUser.selfCertification.features[0] & enums.features.aead)) {
|
||||
supported = false;
|
||||
|
|
|
@ -247,10 +247,11 @@ Message.prototype.getText = function() {
|
|||
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
|
||||
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||
* @param {Date} date (optional) override the creation date of the literal package
|
||||
* @param {Object} userId (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' }
|
||||
* @returns {Promise<Message>} new message with encrypted content
|
||||
* @async
|
||||
*/
|
||||
Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard=false, date=new Date()) {
|
||||
Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard=false, date=new Date(), userId={}) {
|
||||
let symAlgo;
|
||||
let aeadAlgo;
|
||||
let symEncryptedPacket;
|
||||
|
@ -263,9 +264,9 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
|
|||
aeadAlgo = sessionKey.aeadAlgorithm;
|
||||
sessionKey = sessionKey.data;
|
||||
} else if (keys && keys.length) {
|
||||
symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date));
|
||||
if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date)) {
|
||||
aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date));
|
||||
symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date, userId));
|
||||
if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date, userId)) {
|
||||
aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userId));
|
||||
}
|
||||
} else if (passwords && passwords.length) {
|
||||
symAlgo = enums.read(enums.symmetric, config.encryption_cipher);
|
||||
|
@ -278,7 +279,7 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
|
|||
sessionKey = await crypto.generateSessionKey(symAlgo);
|
||||
}
|
||||
|
||||
const msg = await encryptSessionKey(sessionKey, symAlgo, aeadAlgo, keys, passwords, wildcard, date);
|
||||
const msg = await encryptSessionKey(sessionKey, symAlgo, aeadAlgo, keys, passwords, wildcard, date, userId);
|
||||
|
||||
if (config.aead_protect && (config.aead_protect_version !== 4 || aeadAlgo)) {
|
||||
symEncryptedPacket = new packet.SymEncryptedAEADProtected();
|
||||
|
@ -312,16 +313,17 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
|
|||
* @param {Array<Key>} publicKeys (optional) public key(s) for message encryption
|
||||
* @param {Array<String>} passwords (optional) for message encryption
|
||||
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||
* @param {Date} date (optional) override the creation date signature
|
||||
* @param {Date} date (optional) override the date
|
||||
* @param {Object} userId (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' }
|
||||
* @returns {Promise<Message>} new message with encrypted content
|
||||
* @async
|
||||
*/
|
||||
export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKeys, passwords, wildcard=false, date=new Date()) {
|
||||
export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKeys, passwords, wildcard=false, date=new Date(), userId={}) {
|
||||
const packetlist = new packet.List();
|
||||
|
||||
if (publicKeys) {
|
||||
const results = await Promise.all(publicKeys.map(async function(publicKey) {
|
||||
const encryptionKeyPacket = await publicKey.getEncryptionKeyPacket(undefined, date);
|
||||
const encryptionKeyPacket = await publicKey.getEncryptionKeyPacket(undefined, date, userId);
|
||||
if (!encryptionKeyPacket) {
|
||||
throw new Error('Could not find valid key packet for encryption in key ' +
|
||||
publicKey.primaryKey.getKeyId().toHex());
|
||||
|
@ -380,11 +382,12 @@ export async function encryptSessionKey(sessionKey, symAlgo, aeadAlgo, publicKey
|
|||
* Sign the message (the literal data packet of the message)
|
||||
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
|
||||
* @param {Signature} signature (optional) any existing detached signature to add to the message
|
||||
* @param {Date} date} (optional) override the creation time of the signature
|
||||
* @param {Date} date (optional) override the creation time of the signature
|
||||
* @param {Object} userId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<Message>} new message with signed content
|
||||
* @async
|
||||
*/
|
||||
Message.prototype.sign = async function(privateKeys=[], signature=null, date=new Date()) {
|
||||
Message.prototype.sign = async function(privateKeys=[], signature=null, date=new Date(), userId={}) {
|
||||
const packetlist = new packet.List();
|
||||
|
||||
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
||||
|
@ -418,14 +421,14 @@ Message.prototype.sign = async function(privateKeys=[], signature=null, date=new
|
|||
if (privateKey.isPublic()) {
|
||||
throw new Error('Need private key for signing');
|
||||
}
|
||||
const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date);
|
||||
const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date, userId);
|
||||
if (!signingKeyPacket) {
|
||||
throw new Error('Could not find valid key packet for signing in key ' +
|
||||
privateKey.primaryKey.getKeyId().toHex());
|
||||
}
|
||||
const onePassSig = new packet.OnePassSignature();
|
||||
onePassSig.type = signatureType;
|
||||
onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, date);
|
||||
onePassSig.hashAlgorithm = await getPreferredHashAlgo(privateKey, date, userId);
|
||||
onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||||
onePassSig.signingKeyId = signingKeyPacket.getKeyId();
|
||||
if (i === privateKeys.length - 1) {
|
||||
|
@ -467,15 +470,16 @@ Message.prototype.compress = function(compression) {
|
|||
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
|
||||
* @param {Signature} signature (optional) any existing detached signature
|
||||
* @param {Date} date (optional) override the creation time of the signature
|
||||
* @param {Object} userId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<module:signature.Signature>} new detached signature of message content
|
||||
* @async
|
||||
*/
|
||||
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date=new Date()) {
|
||||
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date=new Date(), userId={}) {
|
||||
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
||||
if (!literalDataPacket) {
|
||||
throw new Error('No literal data packet to sign.');
|
||||
}
|
||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date));
|
||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date, userId));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -484,10 +488,11 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null,
|
|||
* @param {Array<module:key.Key>} privateKeys private keys with decrypted secret key data for signing
|
||||
* @param {Signature} signature (optional) any existing detached signature to append
|
||||
* @param {Date} date (optional) override the creationtime of the signature
|
||||
* @param {Object} userId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<module:packet.List>} list of signature packets
|
||||
* @async
|
||||
*/
|
||||
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date=new Date()) {
|
||||
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date=new Date(), userId={}) {
|
||||
const packetlist = new packet.List();
|
||||
|
||||
// If data packet was created from Uint8Array, use binary, otherwise use text
|
||||
|
@ -498,7 +503,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
|||
if (privateKey.isPublic()) {
|
||||
throw new Error('Need private key for signing');
|
||||
}
|
||||
const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date);
|
||||
const signingKeyPacket = await privateKey.getSigningKeyPacket(undefined, date, userId);
|
||||
if (!signingKeyPacket) {
|
||||
throw new Error('Could not find valid key packet for signing in key ' +
|
||||
privateKey.primaryKey.getKeyId().toHex());
|
||||
|
@ -509,7 +514,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
|||
const signaturePacket = new packet.Signature(date);
|
||||
signaturePacket.signatureType = signatureType;
|
||||
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||||
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, date);
|
||||
signaturePacket.hashAlgorithm = await getPreferredHashAlgo(privateKey, date, userId);
|
||||
await signaturePacket.sign(signingKeyPacket, literalDataPacket);
|
||||
return signaturePacket;
|
||||
})).then(signatureList => {
|
||||
|
|
|
@ -115,7 +115,7 @@ export function destroyWorker() {
|
|||
*/
|
||||
|
||||
export function generateKey({ userIds=[], passphrase="", numBits=2048, keyExpirationTime=0, curve="", date=new Date(), subkeys=[{}] }) {
|
||||
userIds = formatUserIds(userIds);
|
||||
userIds = toArray(userIds);
|
||||
const options = { userIds, passphrase, numBits, keyExpirationTime, curve, date, subkeys };
|
||||
if (util.getWebCryptoAll() && numBits < 2048) {
|
||||
throw new Error('numBits should be 2048 or 4096, found: ' + numBits);
|
||||
|
@ -146,7 +146,7 @@ export function generateKey({ userIds=[], passphrase="", numBits=2048, keyExpira
|
|||
* @static
|
||||
*/
|
||||
export function reformatKey({privateKey, userIds=[], passphrase="", keyExpirationTime=0, date}) {
|
||||
userIds = formatUserIds(userIds);
|
||||
userIds = toArray(userIds);
|
||||
const options = { privateKey, userIds, passphrase, keyExpirationTime, date};
|
||||
if (asyncProxy) {
|
||||
return asyncProxy.delegate('reformatKey', options);
|
||||
|
@ -228,17 +228,19 @@ export function encryptKey({ privateKey, passphrase }) {
|
|||
* @param {Boolean} returnSessionKey (optional) if the unencrypted session key should be added to returned object
|
||||
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||
* @param {Date} date (optional) override the creation date of the message and the message signature
|
||||
* @param {Object} fromUserId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @param {Object} toUserId (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' }
|
||||
* @returns {Promise<Object>} encrypted (and optionally signed message) in the form:
|
||||
* {data: ASCII armored message if 'armor' is true,
|
||||
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export function encrypt({ data, dataType, publicKeys, privateKeys, passwords, sessionKey, filename, compression=config.compression, armor=true, detached=false, signature=null, returnSessionKey=false, wildcard=false, date=new Date()}) {
|
||||
export function encrypt({ data, dataType, publicKeys, privateKeys, passwords, sessionKey, filename, compression=config.compression, armor=true, detached=false, signature=null, returnSessionKey=false, wildcard=false, date=new Date(), fromUserId={}, toUserId={} }) {
|
||||
checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
|
||||
|
||||
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
|
||||
return asyncProxy.delegate('encrypt', { data, dataType, publicKeys, privateKeys, passwords, sessionKey, filename, compression, armor, detached, signature, returnSessionKey, wildcard, date });
|
||||
return asyncProxy.delegate('encrypt', { data, dataType, publicKeys, privateKeys, passwords, sessionKey, filename, compression, armor, detached, signature, returnSessionKey, wildcard, date, fromUserId, toUserId });
|
||||
}
|
||||
const result = {};
|
||||
return Promise.resolve().then(async function() {
|
||||
|
@ -248,14 +250,14 @@ export function encrypt({ data, dataType, publicKeys, privateKeys, passwords, se
|
|||
}
|
||||
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
|
||||
if (detached) {
|
||||
const detachedSignature = await message.signDetached(privateKeys, signature, date);
|
||||
const detachedSignature = await message.signDetached(privateKeys, signature, date, fromUserId);
|
||||
result.signature = armor ? detachedSignature.armor() : detachedSignature;
|
||||
} else {
|
||||
message = await message.sign(privateKeys, signature, date);
|
||||
message = await message.sign(privateKeys, signature, date, fromUserId);
|
||||
}
|
||||
}
|
||||
message = message.compress(compression);
|
||||
return message.encrypt(publicKeys, passwords, sessionKey, wildcard, date);
|
||||
return message.encrypt(publicKeys, passwords, sessionKey, wildcard, date, toUserId);
|
||||
|
||||
}).then(encrypted => {
|
||||
if (armor) {
|
||||
|
@ -322,19 +324,20 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
|
|||
* @param {Boolean} armor (optional) if the return value should be ascii armored or the message object
|
||||
* @param {Boolean} detached (optional) if the return value should contain a detached signature
|
||||
* @param {Date} date (optional) override the creation date signature
|
||||
* @param {Object} fromUserId (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' }
|
||||
* @returns {Promise<Object>} signed cleartext in the form:
|
||||
* {data: ASCII armored message if 'armor' is true,
|
||||
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export function sign({ data, dataType, privateKeys, armor=true, detached=false, date=new Date() }) {
|
||||
export function sign({ data, dataType, privateKeys, armor=true, detached=false, date=new Date(), fromUserId={} }) {
|
||||
checkData(data);
|
||||
privateKeys = toArray(privateKeys);
|
||||
|
||||
if (asyncProxy) { // use web worker if available
|
||||
return asyncProxy.delegate('sign', {
|
||||
data, dataType, privateKeys, armor, detached, date
|
||||
data, dataType, privateKeys, armor, detached, date, fromUserId
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -343,10 +346,10 @@ export function sign({ data, dataType, privateKeys, armor=true, detached=false,
|
|||
let message = util.isString(data) ? new CleartextMessage(data) : messageLib.fromBinary(data, dataType);
|
||||
|
||||
if (detached) {
|
||||
const signature = await message.signDetached(privateKeys, undefined, date);
|
||||
const signature = await message.signDetached(privateKeys, undefined, date, fromUserId);
|
||||
result.signature = armor ? signature.armor() : signature;
|
||||
} else {
|
||||
message = await message.sign(privateKeys, undefined, date);
|
||||
message = await message.sign(privateKeys, undefined, date, fromUserId);
|
||||
if (armor) {
|
||||
result.data = message.armor();
|
||||
} else {
|
||||
|
@ -403,20 +406,22 @@ export function verify({ message, publicKeys, signature=null, date=new Date() })
|
|||
* @param {Key|Array<Key>} publicKeys (optional) array of public keys or single key, used to encrypt the key
|
||||
* @param {String|Array<String>} passwords (optional) passwords for the message
|
||||
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||
* @param {Date} date (optional) override the date
|
||||
* @param {Object} toUserId (optional) user ID to encrypt for, e.g. { name:'Phil Zimmermann', email:'phil@openpgp.org' }
|
||||
* @returns {Promise<Message>} the encrypted session key packets contained in a message object
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard=false }) {
|
||||
export function encryptSessionKey({ data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard=false, date=new Date(), toUserId={} }) {
|
||||
checkBinary(data); checkString(algorithm, 'algorithm'); publicKeys = toArray(publicKeys); passwords = toArray(passwords);
|
||||
|
||||
if (asyncProxy) { // use web worker if available
|
||||
return asyncProxy.delegate('encryptSessionKey', { data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard });
|
||||
return asyncProxy.delegate('encryptSessionKey', { data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserId });
|
||||
}
|
||||
|
||||
return Promise.resolve().then(async function() {
|
||||
|
||||
return { message: await messageLib.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard) };
|
||||
return { message: await messageLib.encryptSessionKey(data, algorithm, aeadAlgorithm, publicKeys, passwords, wildcard, date, toUserId) };
|
||||
|
||||
}).catch(onError.bind(null, 'Error encrypting session key'));
|
||||
}
|
||||
|
@ -484,36 +489,6 @@ function checkCleartextOrMessage(message) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format user ids for internal use.
|
||||
*/
|
||||
function formatUserIds(userIds) {
|
||||
if (!userIds) {
|
||||
return userIds;
|
||||
}
|
||||
userIds = toArray(userIds); // normalize to array
|
||||
userIds = userIds.map(id => {
|
||||
if (util.isString(id) && !util.isUserId(id)) {
|
||||
throw new Error('Invalid user id format');
|
||||
}
|
||||
if (util.isUserId(id)) {
|
||||
return id; // user id is already in correct format... no conversion necessary
|
||||
}
|
||||
// name and email address can be empty but must be of the correct type
|
||||
id.name = id.name || '';
|
||||
id.email = id.email || '';
|
||||
if (!util.isString(id.name) || (id.email && !util.isEmailAddress(id.email))) {
|
||||
throw new Error('Invalid user id format');
|
||||
}
|
||||
id.name = id.name.trim();
|
||||
if (id.name.length > 0) {
|
||||
id.name += ' ';
|
||||
}
|
||||
return id.name + '<' + id.email + '>';
|
||||
});
|
||||
return userIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize parameter to an array if it is not undefined.
|
||||
* @param {Object} param the parameter to be normalized
|
||||
|
|
|
@ -41,6 +41,10 @@ function Userid() {
|
|||
* @type {String}
|
||||
*/
|
||||
this.userid = '';
|
||||
|
||||
this.name = '';
|
||||
this.email = '';
|
||||
this.comment = '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +52,17 @@ function Userid() {
|
|||
* @param {Uint8Array} input payload of a tag 13 packet
|
||||
*/
|
||||
Userid.prototype.read = function (bytes) {
|
||||
this.userid = util.decode_utf8(util.Uint8Array_to_str(bytes));
|
||||
this.parse(util.decode_utf8(util.Uint8Array_to_str(bytes)));
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse userid string, e.g. 'John Doe <john@example.com>'
|
||||
*/
|
||||
Userid.prototype.parse = function (userid) {
|
||||
try {
|
||||
Object.assign(this, util.parseUserId(userid));
|
||||
} catch(e) {}
|
||||
this.userid = userid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -59,4 +73,15 @@ Userid.prototype.write = function () {
|
|||
return util.str_to_Uint8Array(util.encode_utf8(this.userid));
|
||||
};
|
||||
|
||||
/**
|
||||
* Set userid string from object, e.g. { name:'Phil Zimmermann', email:'phil@openpgp.org' }
|
||||
*/
|
||||
Userid.prototype.format = function (userid) {
|
||||
if (util.isString(userid)) {
|
||||
userid = util.parseUserId(userid);
|
||||
}
|
||||
Object.assign(this, userid);
|
||||
this.userid = util.formatUserId(userid);
|
||||
};
|
||||
|
||||
export default Userid;
|
||||
|
|
26
src/util.js
26
src/util.js
|
@ -17,11 +17,13 @@
|
|||
|
||||
/**
|
||||
* This object contains utility functions
|
||||
* @requires address-rfc2822
|
||||
* @requires config
|
||||
* @requires encoding/base64
|
||||
* @module util
|
||||
*/
|
||||
|
||||
import rfc2822 from 'address-rfc2822';
|
||||
import config from './config';
|
||||
import util from './util'; // re-import module to access util functions
|
||||
import b64 from './encoding/base64';
|
||||
|
@ -569,11 +571,27 @@ export default {
|
|||
return re.test(data);
|
||||
},
|
||||
|
||||
isUserId: function(data) {
|
||||
if (!util.isString(data)) {
|
||||
return false;
|
||||
/**
|
||||
* Format user id for internal use.
|
||||
*/
|
||||
formatUserId: function(id) {
|
||||
// name and email address can be empty but must be of the correct type
|
||||
if ((id.name && !util.isString(id.name)) || (id.email && !util.isEmailAddress(id.email))) {
|
||||
throw new Error('Invalid user id format');
|
||||
}
|
||||
return new rfc2822.Address(id.name, id.email, id.comment).format();
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse user id.
|
||||
*/
|
||||
parseUserId: function(userid) {
|
||||
try {
|
||||
const [{ phrase: name, address: email, comment }] = rfc2822.parse(userid);
|
||||
return { name, email, comment: comment.replace(/^\(|\)$/g, '') };
|
||||
} catch(e) {
|
||||
throw new Error('Invalid user id format');
|
||||
}
|
||||
return /</.test(data) && />$/.test(data);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -156,8 +156,14 @@ describe('Elliptic Curve Cryptography', function () {
|
|||
return data[name].priv_key;
|
||||
}
|
||||
it('Load public key', function (done) {
|
||||
load_pub_key('romeo');
|
||||
load_pub_key('juliet');
|
||||
const romeoPublic = load_pub_key('romeo');
|
||||
expect(romeoPublic.users[0].userId.name).to.equal('Romeo Montague');
|
||||
expect(romeoPublic.users[0].userId.email).to.equal('romeo@example.net');
|
||||
expect(romeoPublic.users[0].userId.comment).to.equal('secp256k1');
|
||||
const julietPublic = load_pub_key('juliet');
|
||||
expect(julietPublic.users[0].userId.name).to.equal('Juliet Capulet');
|
||||
expect(julietPublic.users[0].userId.email).to.equal('juliet@example.net');
|
||||
expect(julietPublic.users[0].userId.comment).to.equal('secp256k1');
|
||||
done();
|
||||
});
|
||||
it('Load private key', async function () {
|
||||
|
|
|
@ -1297,6 +1297,9 @@ p92yZgB3r2+f6/GIe2+7
|
|||
const primUser = await key.getPrimaryUser();
|
||||
expect(primUser).to.exist;
|
||||
expect(primUser.user.userId.userid).to.equal('Signature Test <signature@test.com>');
|
||||
expect(primUser.user.userId.name).to.equal('Signature Test');
|
||||
expect(primUser.user.userId.email).to.equal('signature@test.com');
|
||||
expect(primUser.user.userId.comment).to.equal('');
|
||||
expect(primUser.selfCertification).to.be.an.instanceof(openpgp.packet.Signature);
|
||||
});
|
||||
|
||||
|
@ -1315,13 +1318,16 @@ p92yZgB3r2+f6/GIe2+7
|
|||
});
|
||||
|
||||
it('Generate key - single userid', function() {
|
||||
const userId = 'test <a@b.com>';
|
||||
const userId = { name: 'test', email: 'a@b.com', comment: 'test comment' };
|
||||
const opt = {numBits: 512, userIds: userId, passphrase: '123'};
|
||||
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
|
||||
return openpgp.generateKey(opt).then(function(key) {
|
||||
key = key.key;
|
||||
expect(key.users.length).to.equal(1);
|
||||
expect(key.users[0].userId.userid).to.equal(userId);
|
||||
expect(key.users[0].userId.userid).to.equal('test <a@b.com> (test comment)');
|
||||
expect(key.users[0].userId.name).to.equal(userId.name);
|
||||
expect(key.users[0].userId.email).to.equal(userId.email);
|
||||
expect(key.users[0].userId.comment).to.equal(userId.comment);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1517,6 +1523,61 @@ p92yZgB3r2+f6/GIe2+7
|
|||
expect(signatures[3].valid).to.be.null;
|
||||
});
|
||||
|
||||
it('Encrypt - latest created user', async function() {
|
||||
let publicKey = openpgp.key.readArmored(multi_uid_key).keys[0];
|
||||
const privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
|
||||
await privateKey.decrypt('hello world');
|
||||
// Set second user to prefer aes128. We should select this user by default, since it was created later.
|
||||
publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
|
||||
const encrypted = await openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, armor: false});
|
||||
expect(encrypted.message.packets[0].sessionKeyAlgorithm).to.equal('aes128');
|
||||
});
|
||||
|
||||
it('Encrypt - primary user', async function() {
|
||||
let publicKey = openpgp.key.readArmored(multi_uid_key).keys[0];
|
||||
const privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
|
||||
await privateKey.decrypt('hello world');
|
||||
// Set first user to primary. We should select this user by default.
|
||||
publicKey.users[0].selfCertifications[0].isPrimaryUserID = true;
|
||||
// Set first user to prefer aes128.
|
||||
publicKey.users[0].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
|
||||
const encrypted = await openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, armor: false});
|
||||
expect(encrypted.message.packets[0].sessionKeyAlgorithm).to.equal('aes128');
|
||||
});
|
||||
|
||||
it('Encrypt - specific user', async function() {
|
||||
let publicKey = openpgp.key.readArmored(multi_uid_key).keys[0];
|
||||
const privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
|
||||
await privateKey.decrypt('hello world');
|
||||
// Set first user to primary. We won't select this user, this is to test that.
|
||||
publicKey.users[0].selfCertifications[0].isPrimaryUserID = true;
|
||||
// Set second user to prefer aes128. We will select this user.
|
||||
publicKey.users[1].selfCertifications[0].preferredSymmetricAlgorithms = [openpgp.enums.symmetric.aes128];
|
||||
const encrypted = await openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, toUserId: {name: 'Test User', email: 'b@c.com'}, armor: false});
|
||||
expect(encrypted.message.packets[0].sessionKeyAlgorithm).to.equal('aes128');
|
||||
await expect(openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, toUserId: {name: 'Test User', email: 'c@c.com'}, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID');
|
||||
});
|
||||
|
||||
it('Sign - specific user', async function() {
|
||||
let publicKey = openpgp.key.readArmored(multi_uid_key).keys[0];
|
||||
const privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
|
||||
await privateKey.decrypt('hello world');
|
||||
const privateKeyClone = openpgp.key.readArmored(priv_key_rsa).keys[0];
|
||||
// Duplicate user
|
||||
privateKey.users.push(privateKeyClone.users[0]);
|
||||
// Set first user to primary. We won't select this user, this is to test that.
|
||||
privateKey.users[0].selfCertifications[0].isPrimaryUserID = true;
|
||||
// Change userid of the first user so that we don't select it. This also makes this user invalid.
|
||||
privateKey.users[0].userId.parse('Test User <b@c.com>');
|
||||
// Set second user to prefer aes128. We will select this user.
|
||||
privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
|
||||
const signed = await openpgp.sign({data: 'hello', privateKeys: privateKey, fromUserId: {name: 'Test McTestington', email: 'test@example.com'}, armor: false});
|
||||
expect(signed.message.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
|
||||
const encrypted = await openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, fromUserId: {name: 'Test McTestington', email: 'test@example.com'}, detached: true, armor: false});
|
||||
expect(encrypted.signature.packets[0].hashAlgorithm).to.equal(openpgp.enums.hash.sha512);
|
||||
await expect(openpgp.encrypt({data: 'hello', publicKeys: publicKey, privateKeys: privateKey, fromUserId: {name: 'Not Test McTestington', email: 'test@example.com'}, detached: true, armor: false})).to.be.rejectedWith('Could not find user that matches that user ID');
|
||||
});
|
||||
|
||||
it('Reformat key without passphrase', function() {
|
||||
const userId1 = 'test1 <a@b.com>';
|
||||
const userId2 = 'test2 <b@a.com>';
|
||||
|
|
|
@ -371,73 +371,57 @@ describe('OpenPGP.js public api tests', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('generateKey - unit tests', function() {
|
||||
let keyGenStub;
|
||||
let keyObjStub;
|
||||
let getWebCryptoAllStub;
|
||||
describe('generateKey - validate user ids', function() {
|
||||
let rsaGenStub;
|
||||
let rsaGenValue = openpgp.crypto.publicKey.rsa.generate(2048, "10001");
|
||||
|
||||
beforeEach(function() {
|
||||
keyObjStub = {
|
||||
armor: function() {
|
||||
return 'priv_key';
|
||||
},
|
||||
toPublic: function() {
|
||||
return {
|
||||
armor: function() {
|
||||
return 'pub_key';
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
keyGenStub = stub(openpgp.key, 'generate');
|
||||
keyGenStub.returns(resolves(keyObjStub));
|
||||
getWebCryptoAllStub = stub(openpgp.util, 'getWebCryptoAll');
|
||||
rsaGenStub = stub(openpgp.crypto.publicKey.rsa, 'generate');
|
||||
rsaGenStub.returns(rsaGenValue);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
keyGenStub.restore();
|
||||
openpgp.destroyWorker();
|
||||
getWebCryptoAllStub.restore();
|
||||
rsaGenStub.restore();
|
||||
});
|
||||
|
||||
it('should fail for invalid user name', function() {
|
||||
it('should fail for invalid user name', async function() {
|
||||
const opt = {
|
||||
userIds: [{ name: {}, email: 'text@example.com' }]
|
||||
};
|
||||
const test = openpgp.generateKey.bind(null, opt);
|
||||
expect(test).to.throw(/Invalid user id format/);
|
||||
const test = openpgp.generateKey(opt);
|
||||
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/);
|
||||
});
|
||||
|
||||
it('should fail for invalid user email address', function() {
|
||||
it('should fail for invalid user email address', async function() {
|
||||
const opt = {
|
||||
userIds: [{ name: 'Test User', email: 'textexample.com' }]
|
||||
};
|
||||
const test = openpgp.generateKey.bind(null, opt);
|
||||
expect(test).to.throw(/Invalid user id format/);
|
||||
const test = openpgp.generateKey(opt);
|
||||
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/);
|
||||
});
|
||||
|
||||
it('should fail for invalid user email address', function() {
|
||||
it('should fail for invalid user email address', async function() {
|
||||
const opt = {
|
||||
userIds: [{ name: 'Test User', email: 'text@examplecom' }]
|
||||
};
|
||||
const test = openpgp.generateKey.bind(null, opt);
|
||||
expect(test).to.throw(/Invalid user id format/);
|
||||
const test = openpgp.generateKey(opt);
|
||||
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/);
|
||||
});
|
||||
|
||||
it('should fail for invalid string user id', function() {
|
||||
it('should fail for invalid string user id', async function() {
|
||||
const opt = {
|
||||
userIds: ['Test User text@example.com>']
|
||||
};
|
||||
const test = openpgp.generateKey.bind(null, opt);
|
||||
expect(test).to.throw(/Invalid user id format/);
|
||||
const test = openpgp.generateKey(opt);
|
||||
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/);
|
||||
});
|
||||
|
||||
it('should fail for invalid single string user id', function() {
|
||||
it('should fail for invalid single string user id', async function() {
|
||||
const opt = {
|
||||
userIds: 'Test User text@example.com>'
|
||||
};
|
||||
const test = openpgp.generateKey.bind(null, opt);
|
||||
expect(test).to.throw(/Invalid user id format/);
|
||||
const test = openpgp.generateKey(opt);
|
||||
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/);
|
||||
});
|
||||
|
||||
it('should work for valid single string user id', function() {
|
||||
|
@ -481,6 +465,36 @@ describe('OpenPGP.js public api tests', function() {
|
|||
};
|
||||
return openpgp.generateKey(opt);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateKey - unit tests', function() {
|
||||
let keyGenStub;
|
||||
let keyObjStub;
|
||||
let getWebCryptoAllStub;
|
||||
|
||||
beforeEach(function() {
|
||||
keyObjStub = {
|
||||
armor: function() {
|
||||
return 'priv_key';
|
||||
},
|
||||
toPublic: function() {
|
||||
return {
|
||||
armor: function() {
|
||||
return 'pub_key';
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
keyGenStub = stub(openpgp.key, 'generate');
|
||||
keyGenStub.returns(resolves(keyObjStub));
|
||||
getWebCryptoAllStub = stub(openpgp.util, 'getWebCryptoAll');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
keyGenStub.restore();
|
||||
openpgp.destroyWorker();
|
||||
getWebCryptoAllStub.restore();
|
||||
});
|
||||
|
||||
it('should have default params set', function() {
|
||||
const now = openpgp.util.normalizeDate(new Date());
|
||||
|
@ -492,7 +506,7 @@ describe('OpenPGP.js public api tests', function() {
|
|||
};
|
||||
return openpgp.generateKey(opt).then(function(newKey) {
|
||||
expect(keyGenStub.withArgs({
|
||||
userIds: ['Test User <text@example.com>'],
|
||||
userIds: [{ name: 'Test User', email: 'text@example.com' }],
|
||||
passphrase: 'secret',
|
||||
numBits: 2048,
|
||||
keyExpirationTime: 0,
|
||||
|
|
|
@ -116,37 +116,6 @@ describe('Util unit tests', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isUserId', function() {
|
||||
it('should return true for valid user id', function() {
|
||||
const data = 'Test User <test@example.com>';
|
||||
expect(openpgp.util.isUserId(data)).to.be.true;
|
||||
});
|
||||
it('should return false for invalid user id', function() {
|
||||
const data = 'Test User test@example.com>';
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
it('should return false for invalid user id', function() {
|
||||
const data = 'Test User <test@example.com';
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
it('should return false for invalid user id', function() {
|
||||
const data = 'Test User test@example.com';
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
it('should return false for empty string', function() {
|
||||
const data = '';
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
it('should return false for undefined', function() {
|
||||
let data;
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
it('should return false for Object', function() {
|
||||
const data = {};
|
||||
expect(openpgp.util.isUserId(data)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTransferables', function() {
|
||||
let zero_copyVal;
|
||||
const buf1 = new Uint8Array(1);
|
||||
|
|
Loading…
Reference in New Issue
Block a user