Require User IDs to be objects; refactor UserIDPacket (#1187)

- `openpgp.generateKey` now expects `userIds` in object format
  (strings are no longer supported)
- Remove `util.parseUserId` and `util.formatUserId`
- Replace `UserIDPacket#format` with `UserIDPacket.fromObject`
This commit is contained in:
larabr 2021-01-06 16:42:44 +01:00 committed by Daniel Huigens
parent 724775816f
commit c23ed58387
10 changed files with 120 additions and 188 deletions

25
openpgp.d.ts vendored
View File

@ -14,10 +14,10 @@ export function readKey(data: Uint8Array): Promise<Key>;
export function readArmoredKeys(armoredText: string): Promise<Key[]>; export function readArmoredKeys(armoredText: string): Promise<Key[]>;
export function readKeys(data: Uint8Array): Promise<Key[]>; export function readKeys(data: Uint8Array): Promise<Key[]>;
export function generateKey(options: KeyOptions): Promise<KeyPair>; export function generateKey(options: KeyOptions): Promise<KeyPair>;
export function generateSessionKey(options: { publicKeys: Key[], date?: Date, toUserIds?: UserId[] }): Promise<SessionKey>; export function generateSessionKey(options: { publicKeys: Key[], date?: Date, toUserIds?: UserID[] }): Promise<SessionKey>;
export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; }): Promise<Key>; export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; }): Promise<Key>;
export function encryptKey(options: { privateKey: Key; passphrase?: string | string[] }): Promise<Key>; export function encryptKey(options: { privateKey: Key; passphrase?: string | string[] }): Promise<Key>;
export function reformatKey(options: { privateKey: Key; userIds?: (string | UserId)[]; passphrase?: string; keyExpirationTime?: number; }): Promise<KeyPair>; export function reformatKey(options: { privateKey: Key; userIds?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; }): Promise<KeyPair>;
export class Key { export class Key {
constructor(packetlist: PacketList<AnyPacket>); constructor(packetlist: PacketList<AnyPacket>);
@ -29,7 +29,7 @@ export class Key {
public armor(): string; public armor(): string;
public decrypt(passphrase: string | string[], keyId?: Keyid): Promise<void>; // throws on error public decrypt(passphrase: string | string[], keyId?: Keyid): Promise<void>; // throws on error
public encrypt(passphrase: string | string[]): Promise<void>; // throws on error public encrypt(passphrase: string | string[]): Promise<void>; // throws on error
public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyId?: Keyid, userId?: UserId): Promise<Date | typeof Infinity | null>; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid. public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyId?: Keyid, userId?: UserID): Promise<Date | typeof Infinity | null>; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid.
public getKeyIds(): Keyid[]; public getKeyIds(): Keyid[];
public getPrimaryUser(): Promise<PrimaryUser>; // throws on error public getPrimaryUser(): Promise<PrimaryUser>; // throws on error
public getUserIds(): string[]; public getUserIds(): string[];
@ -41,8 +41,8 @@ export class Key {
public isRevoked(): Promise<boolean>; public isRevoked(): Promise<boolean>;
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date): Promise<Key>; public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date): Promise<Key>;
public getRevocationCertificate(): Promise<Stream<string> | string | undefined>; public getRevocationCertificate(): Promise<Stream<string> | string | undefined>;
public getEncryptionKey(keyid?: Keyid, date?: Date | null, userId?: UserId): Promise<Key | SubKey>; public getEncryptionKey(keyid?: Keyid, date?: Date | null, userId?: UserID): Promise<Key | SubKey>;
public getSigningKey(keyid?: Keyid, date?: Date | null, userId?: UserId): Promise<Key | SubKey>; public getSigningKey(keyid?: Keyid, date?: Date | null, userId?: UserID): Promise<Key | SubKey>;
public getKeys(keyId?: Keyid): (Key | SubKey)[]; public getKeys(keyId?: Keyid): (Key | SubKey)[];
public isDecrypted(): boolean; public isDecrypted(): boolean;
public getFingerprint(): string; public getFingerprint(): string;
@ -419,6 +419,7 @@ export class OnePassSignaturePacket extends BasePacket {
export class UserIDPacket extends BasePacket { export class UserIDPacket extends BasePacket {
public tag: enums.packet.userID; public tag: enums.packet.userID;
public userid: string; public userid: string;
static fromObject(userId: UserID): UserIDPacket;
} }
export class SignaturePacket extends BasePacket { export class SignaturePacket extends BasePacket {
@ -530,7 +531,7 @@ export namespace stream {
/* ############## v5 GENERAL #################### */ /* ############## v5 GENERAL #################### */
export interface UserId { name?: string; email?: string; comment?: string; } export interface UserID { name?: string; email?: string; comment?: string; }
export interface SessionKey { data: Uint8Array; algorithm: string; } export interface SessionKey { data: Uint8Array; algorithm: string; }
@ -558,9 +559,9 @@ interface EncryptOptions {
/** (optional) use a key ID of 0 instead of the public key IDs */ /** (optional) use a key ID of 0 instead of the public key IDs */
wildcard?: boolean; wildcard?: boolean;
/** (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' } */ /** (optional) user ID to sign with, e.g. { name:'Steve Sender', email:'steve@openpgp.org' } */
fromUserId?: UserId; fromUserId?: UserID;
/** (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' } */ /** (optional) user ID to encrypt for, e.g. { name:'Robert Receiver', email:'robert@openpgp.org' } */
toUserId?: UserId; toUserId?: UserID;
} }
interface DecryptOptions { interface DecryptOptions {
@ -592,7 +593,7 @@ interface SignOptions {
dataType?: DataPacketType; dataType?: DataPacketType;
detached?: boolean; detached?: boolean;
date?: Date; date?: Date;
fromUserId?: UserId; fromUserId?: UserID;
} }
interface VerifyOptions { interface VerifyOptions {
@ -620,7 +621,7 @@ interface KeyPair {
export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1'; export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1';
interface KeyOptions { interface KeyOptions {
userIds: UserId[]; // generating a key with no user defined results in error userIds: UserID|UserID[];
passphrase?: string; passphrase?: string;
type?: 'ecc' | 'rsa'; type?: 'ecc' | 'rsa';
curve?: EllipticCurveName; curve?: EllipticCurveName;
@ -890,10 +891,6 @@ declare namespace util {
*/ */
function hexToStr(hex: string): string; function hexToStr(hex: string): string;
function parseUserId(userid: string): UserId;
function formatUserId(userid: UserId): string;
function normalizeDate(date: Date | null): Date | null; function normalizeDate(date: Date | null): Date | null;
/** /**

View File

@ -156,9 +156,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) {
return algos; return algos;
} }
const userIdPacket = new UserIDPacket(); const userIdPacket = UserIDPacket.fromObject(userId);
userIdPacket.format(userId);
const dataToSign = {}; const dataToSign = {};
dataToSign.userId = userIdPacket; dataToSign.userId = userIdPacket;
dataToSign.key = secretKeyPacket; dataToSign.key = secretKeyPacket;

View File

@ -289,7 +289,7 @@ export class Message {
* Generate a new session key object, taking the algorithm preferences of the passed public keys into account, if any. * Generate a new session key object, taking the algorithm preferences of the passed public keys into account, if any.
* @param {Array<Key>} keys (optional) public key(s) to select algorithm preferences for * @param {Array<Key>} keys (optional) public key(s) to select algorithm preferences for
* @param {Date} date (optional) date to select algorithm preferences at * @param {Date} date (optional) date to select algorithm preferences at
* @param {Array} userIds (optional) user IDs to select algorithm preferences for * @param {Array<Object>} userIds (optional) user IDs to select algorithm preferences for
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm * @returns {Promise<{ data: Uint8Array, algorithm: String }>} object with session key data and algorithm
* @async * @async
*/ */
@ -309,7 +309,7 @@ export class Message {
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] } * @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 {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 {Date} date (optional) override the creation date of the literal package
* @param {Array} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }] * @param {Array<Object>} userIds (optional) user IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
* @param {Boolean} streaming (optional) whether to process data as a stream * @param {Boolean} streaming (optional) whether to process data as a stream
* @returns {Promise<Message>} new message with encrypted content * @returns {Promise<Message>} new message with encrypted content
* @async * @async

View File

@ -64,7 +64,7 @@ if (globalThis.ReadableStream) {
/** /**
* Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type. * Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
* @param {ecc|rsa} type (optional) The primary key algorithm type: ECC (default) or RSA * @param {ecc|rsa} type (optional) The primary key algorithm type: ECC (default) or RSA
* @param {Array<String|Object>} userIds User IDs as strings or objects: 'Jo Doe <info@jo.com>' or { name:'Jo Doe', email:'info@jo.com' } * @param {Object|Array<Object>} userIds User IDs as objects: { name:'Jo Doe', email:'info@jo.com' }
* @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key * @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key
* @param {Number} rsaBits (optional) Number of bits for RSA keys, defaults to 4096 * @param {Number} rsaBits (optional) Number of bits for RSA keys, defaults to 4096
* @param {String} curve (optional) Elliptic curve for ECC keys: * @param {String} curve (optional) Elliptic curve for ECC keys:
@ -104,7 +104,7 @@ export function generateKey({ userIds = [], passphrase = "", type = "ecc", rsaBi
/** /**
* Reformats signature packets for a key and rewraps key object. * Reformats signature packets for a key and rewraps key object.
* @param {Key} privateKey Private key to reformat * @param {Key} privateKey Private key to reformat
* @param {Array<String|Object>} userIds User IDs as strings or objects: 'Jo Doe <info@jo.com>' or { name:'Jo Doe', email:'info@jo.com' } * @param {Object|Array<Object>} userIds User IDs as objects: { name:'Jo Doe', email:'info@jo.com' }
* @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key * @param {String} passphrase (optional) The passphrase used to encrypt the resulting private key
* @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires * @param {Number} keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
* @returns {Promise<Object>} The generated key object in the form: * @returns {Promise<Object>} The generated key object in the form:
@ -222,8 +222,8 @@ export function encryptKey({ privateKey, passphrase }) {
* @param {Signature} signature (optional) a detached signature to add to the encrypted message * @param {Signature} signature (optional) a detached signature to add to the encrypted message
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs * @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 signature * @param {Date} date (optional) override the creation date of the message signature
* @param {Array} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] * @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }] * @param {Array<Object>} toUserIds (optional) array of user IDs to encrypt for, one per key in `publicKeys`, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false) * @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
* @async * @async
* @static * @static
@ -312,7 +312,7 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
* @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any. * @param {'web'|'ponyfill'|'node'|false} streaming (optional) whether to return data as a stream. Defaults to the type of stream `message` was created from, if any.
* @param {Boolean} detached (optional) if the return value should contain a detached signature * @param {Boolean} detached (optional) if the return value should contain a detached signature
* @param {Date} date (optional) override the creation date of the signature * @param {Date} date (optional) override the creation date of the signature
* @param {Array} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }] * @param {Array<Object>} fromUserIds (optional) array of user IDs to sign with, one per key in `privateKeys`, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false) * @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} (String if `armor` was true, the default; Uint8Array if `armor` was false)
* @async * @async
* @static * @static

View File

@ -19,9 +19,11 @@
* @requires enums * @requires enums
* @requires util * @requires util
*/ */
import emailAddresses from 'email-addresses';
import enums from '../enums'; import enums from '../enums';
import util from '../util'; import util from '../util';
import config from '../config';
/** /**
* Implementation of the User ID Packet (Tag 13) * Implementation of the User ID Packet (Tag 13)
@ -47,20 +49,43 @@ class UserIDPacket {
this.comment = ''; this.comment = '';
} }
/**
* Create UserIDPacket instance from object
* @param {Object} userId object specifying userId name, email and comment
* @returns {module:userid.UserIDPacket}
* @static
*/
static fromObject(userId) {
if (util.isString(userId) ||
(userId.name && !util.isString(userId.name)) ||
(userId.email && !util.isEmailAddress(userId.email)) ||
(userId.comment && !util.isString(userId.comment))) {
throw new Error('Invalid user ID format');
}
const packet = new UserIDPacket();
Object.assign(packet, userId);
const components = [];
if (packet.name) components.push(packet.name);
if (packet.comment) components.push(`(${packet.comment})`);
if (packet.email) components.push(`<${packet.email}>`);
packet.userid = components.join(' ');
return packet;
}
/** /**
* Parsing function for a user id packet (tag 13). * Parsing function for a user id packet (tag 13).
* @param {Uint8Array} input payload of a tag 13 packet * @param {Uint8Array} input payload of a tag 13 packet
*/ */
read(bytes) { read(bytes) {
this.parse(util.decodeUtf8(bytes)); const userid = util.decodeUtf8(bytes);
} if (userid.length > config.maxUseridLength) {
throw new Error('User ID string is too long');
/** }
* Parse userid string, e.g. 'John Doe <john@example.com>'
*/
parse(userid) {
try { try {
Object.assign(this, util.parseUserId(userid)); const { name, address: email, comments } = emailAddresses.parseOneAddress({ input: userid, atInDisplayName: true });
this.comment = comments.replace(/^\(|\)$/g, '');
this.name = name;
this.email = email;
} catch (e) {} } catch (e) {}
this.userid = userid; this.userid = userid;
} }
@ -72,17 +97,6 @@ class UserIDPacket {
write() { write() {
return util.encodeUtf8(this.userid); return util.encodeUtf8(this.userid);
} }
/**
* Set userid string from object, e.g. { name:'Phil Zimmermann', email:'phil@openpgp.org' }
*/
format(userid) {
if (util.isString(userid)) {
userid = util.parseUserId(userid);
}
Object.assign(this, userid);
this.userid = util.formatUserId(userid);
}
} }
export default UserIDPacket; export default UserIDPacket;

View File

@ -26,7 +26,6 @@
* @module util * @module util
*/ */
import emailAddresses from 'email-addresses';
import stream from 'web-stream-tools'; import stream from 'web-stream-tools';
import config from './config'; import config from './config';
import util from './util'; // re-import module to access util functions import util from './util'; // re-import module to access util functions
@ -598,44 +597,6 @@ export default {
return re.test(data); return re.test(data);
}, },
/**
* Format user id for internal use.
*/
formatUserId: function(id) {
// name, email address and comment can be empty but must be of the correct type
if ((id.name && !util.isString(id.name)) ||
(id.email && !util.isEmailAddress(id.email)) ||
(id.comment && !util.isString(id.comment))) {
throw new Error('Invalid user id format');
}
const components = [];
if (id.name) {
components.push(id.name);
}
if (id.comment) {
components.push(`(${id.comment})`);
}
if (id.email) {
components.push(`<${id.email}>`);
}
return components.join(' ');
},
/**
* Parse user id.
*/
parseUserId: function(userid) {
if (userid.length > config.maxUseridLength) {
throw new Error('User id string is too long');
}
try {
const { name, address: email, comments } = emailAddresses.parseOneAddress({ input: userid, atInDisplayName: true });
return { name, email, comment: comments.replace(/^\(|\)$/g, '') };
} catch (e) {
throw new Error('Invalid user id format');
}
},
/** /**
* Normalize line endings to <CR><LF> * Normalize line endings to <CR><LF>
* Support any encoding where CR=0x0D, LF=0x0A * Support any encoding where CR=0x0D, LF=0x0A

View File

@ -2103,7 +2103,7 @@ function versionSpecificTests() {
} }
expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
}; };
const opt = { userIds: 'test <a@b.com>', passphrase: 'hello' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' };
return openpgp.generateKey(opt).then(async function(key) { return openpgp.generateKey(opt).then(async function(key) {
testPref(key.key); testPref(key.key);
testPref(await openpgp.readArmoredKey(key.publicKeyArmored)); testPref(await openpgp.readArmoredKey(key.publicKeyArmored));
@ -2148,7 +2148,7 @@ function versionSpecificTests() {
} }
expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures);
}; };
const opt = { userIds: 'test <a@b.com>', passphrase: 'hello' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' };
try { try {
const key = await openpgp.generateKey(opt); const key = await openpgp.generateKey(opt);
testPref(key.key); testPref(key.key);
@ -2162,7 +2162,7 @@ function versionSpecificTests() {
}); });
it('Generated key is not unlocked by default', function() { it('Generated key is not unlocked by default', function() {
const opt = { userIds: 'test <a@b.com>', passphrase: '123' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: '123' };
let key; let key;
return openpgp.generateKey(opt).then(function(newKey) { return openpgp.generateKey(opt).then(function(newKey) {
key = newKey.key; key = newKey.key;
@ -2259,27 +2259,27 @@ function versionSpecificTests() {
}); });
it('Generate key - multi userid', function() { it('Generate key - multi userid', function() {
const userId1 = 'test <a@b.com>'; const userId1 = { name: 'test', email: 'a@b.com' };
const userId2 = 'test <b@c.com>'; const userId2 = { name: 'test', email: 'b@c.com' };
const opt = { userIds: [userId1, userId2], passphrase: '123' }; const opt = { userIds: [userId1, userId2], passphrase: '123' };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function(key) {
key = key.key; key = key.key;
expect(key.users.length).to.equal(2); expect(key.users.length).to.equal(2);
expect(key.users[0].userId.userid).to.equal(userId1); expect(key.users[0].userId.userid).to.equal('test <a@b.com>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.users[1].userId.userid).to.equal(userId2); expect(key.users[1].userId.userid).to.equal('test <b@c.com>');
expect(key.users[1].selfCertifications[0].isPrimaryUserID).to.be.null; expect(key.users[1].selfCertifications[0].isPrimaryUserID).to.be.null;
}); });
}); });
it('Generate key - default values', function() { it('Generate key - default values', function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: [userId] }; const opt = { userIds: [userId] };
return openpgp.generateKey(opt).then(function({ key }) { return openpgp.generateKey(opt).then(function({ key }) {
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa');
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subKeys).to.have.length(1); expect(key.subKeys).to.have.length(1);
expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
@ -2287,12 +2287,12 @@ function versionSpecificTests() {
}); });
it('Generate key - two subkeys with default values', function() { it('Generate key - two subkeys with default values', function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: [userId], passphrase: '123', subkeys:[{},{}] }; const opt = { userIds: [userId], passphrase: '123', subkeys:[{},{}] };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function(key) {
key = key.key; key = key.key;
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subKeys).to.have.length(2); expect(key.subKeys).to.have.length(2);
expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
@ -2305,12 +2305,12 @@ function versionSpecificTests() {
const minRsaBits = openpgp.config.minRsaBits; const minRsaBits = openpgp.config.minRsaBits;
openpgp.config.minRsaBits = rsaBits; openpgp.config.minRsaBits = rsaBits;
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIds: [userId], passphrase: '123', subkeys:[{},{}] }; const opt = { type: 'rsa', rsaBits, userIds: [userId], passphrase: '123', subkeys:[{},{}] };
try { try {
const { key } = await openpgp.generateKey(opt); const { key } = await openpgp.generateKey(opt);
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subKeys).to.have.length(2); expect(key.subKeys).to.have.length(2);
expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
@ -2321,12 +2321,12 @@ function versionSpecificTests() {
}); });
it('Generate key - one signing subkey', function() { it('Generate key - one signing subkey', function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: [userId], passphrase: '123', subkeys:[{}, { sign: true }] }; const opt = { userIds: [userId], passphrase: '123', subkeys:[{}, { sign: true }] };
return openpgp.generateKey(opt).then(async function({ privateKeyArmored }) { return openpgp.generateKey(opt).then(async function({ privateKeyArmored }) {
const key = await openpgp.readArmoredKey(privateKeyArmored); const key = await openpgp.readArmoredKey(privateKeyArmored);
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subKeys).to.have.length(2); expect(key.subKeys).to.have.length(2);
expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
@ -2337,7 +2337,7 @@ function versionSpecificTests() {
}); });
it('Reformat key - one signing subkey', function() { it('Reformat key - one signing subkey', function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: [userId], passphrase: '123', subkeys:[{}, { sign: true }] }; const opt = { userIds: [userId], passphrase: '123', subkeys:[{}, { sign: true }] };
return openpgp.generateKey(opt).then(async function({ key }) { return openpgp.generateKey(opt).then(async function({ key }) {
await key.decrypt('123'); await key.decrypt('123');
@ -2345,7 +2345,7 @@ function versionSpecificTests() {
}).then(async function({ privateKeyArmored }) { }).then(async function({ privateKeyArmored }) {
const key = await openpgp.readArmoredKey(privateKeyArmored); const key = await openpgp.readArmoredKey(privateKeyArmored);
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.subKeys).to.have.length(2); expect(key.subKeys).to.have.length(2);
expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); expect(key.subKeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh');
@ -2360,12 +2360,12 @@ function versionSpecificTests() {
const minRsaBits = openpgp.config.minRsaBits; const minRsaBits = openpgp.config.minRsaBits;
openpgp.config.minRsaBits = rsaBits; openpgp.config.minRsaBits = rsaBits;
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIds: [userId], passphrase: '123', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; const opt = { type: 'rsa', rsaBits, userIds: [userId], passphrase: '123', subkeys:[{ type: 'ecc', curve: 'curve25519' }] };
try { try {
const { key } = await openpgp.generateKey(opt); const { key } = await openpgp.generateKey(opt);
expect(key.users.length).to.equal(1); 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>');
expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true;
expect(key.getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); expect(key.getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign');
expect(key.getAlgorithmInfo().bits).to.equal(opt.rsaBits); expect(key.getAlgorithmInfo().bits).to.equal(opt.rsaBits);
@ -2376,7 +2376,7 @@ function versionSpecificTests() {
}); });
it('Encrypt key with new passphrase', async function() { it('Encrypt key with new passphrase', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: userId, passphrase: 'passphrase' }; const opt = { userIds: userId, passphrase: 'passphrase' };
const key = (await openpgp.generateKey(opt)).key; const key = (await openpgp.generateKey(opt)).key;
const armor1 = key.armor(); const armor1 = key.armor();
@ -2396,7 +2396,7 @@ function versionSpecificTests() {
it('Generate key - ensure keyExpirationTime works', function() { it('Generate key - ensure keyExpirationTime works', function() {
const expect_delta = 365 * 24 * 60 * 60; const expect_delta = 365 * 24 * 60 * 60;
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { userIds: userId, passphrase: '123', keyExpirationTime: expect_delta }; const opt = { userIds: userId, passphrase: '123', keyExpirationTime: expect_delta };
return openpgp.generateKey(opt).then(async function(key) { return openpgp.generateKey(opt).then(async function(key) {
key = key.key; key = key.key;
@ -2494,46 +2494,46 @@ function versionSpecificTests() {
}); });
it('Reformat key without passphrase', function() { it('Reformat key without passphrase', function() {
const userId1 = 'test1 <a@b.com>'; const userId1 = { name: 'test', email: 'a@b.com' };
const userId2 = 'test2 <b@a.com>'; const userId2 = { name: 'test', email: 'b@c.com' };
const opt = { userIds: userId1 }; const opt = { userIds: userId1 };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function(key) {
key = key.key; key = key.key;
expect(key.users.length).to.equal(1); expect(key.users.length).to.equal(1);
expect(key.users[0].userId.userid).to.equal(userId1); expect(key.users[0].userId.userid).to.equal('test <a@b.com>');
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
opt.privateKey = key; opt.privateKey = key;
opt.userIds = userId2; opt.userIds = userId2;
return openpgp.reformatKey(opt).then(function(newKey) { return openpgp.reformatKey(opt).then(function(newKey) {
newKey = newKey.key; newKey = newKey.key;
expect(newKey.users.length).to.equal(1); expect(newKey.users.length).to.equal(1);
expect(newKey.users[0].userId.userid).to.equal(userId2); expect(newKey.users[0].userId.userid).to.equal('test <b@c.com>');
expect(newKey.isDecrypted()).to.be.true; expect(newKey.isDecrypted()).to.be.true;
}); });
}); });
}); });
it('Reformat key with no subkey with passphrase', async function() { it('Reformat key with no subkey with passphrase', async function() {
const userId = 'test1 <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const key = await openpgp.readArmoredKey(key_without_subkey); const key = await openpgp.readArmoredKey(key_without_subkey);
const opt = { privateKey: key, userIds: [userId], passphrase: "test" }; const opt = { privateKey: key, userIds: [userId], passphrase: "test" };
return openpgp.reformatKey(opt).then(function(newKey) { return openpgp.reformatKey(opt).then(function(newKey) {
newKey = newKey.key; newKey = newKey.key;
expect(newKey.users.length).to.equal(1); expect(newKey.users.length).to.equal(1);
expect(newKey.users[0].userId.userid).to.equal(userId); expect(newKey.users[0].userId.userid).to.equal('test <a@b.com>');
expect(newKey.isDecrypted()).to.be.false; expect(newKey.isDecrypted()).to.be.false;
}); });
}); });
it('Reformat key with two subkeys with passphrase', function() { it('Reformat key with two subkeys with passphrase', function() {
const userId1 = 'test <a@b.com>'; const userId1 = { name: 'test', email: 'a@b.com' };
const userId2 = 'test <b@c.com>'; const userId2 = { name: 'test', email: 'b@c.com' };
const now = util.normalizeDate(new Date()); const now = util.normalizeDate(new Date());
const before = util.normalizeDate(new Date(0)); const before = util.normalizeDate(new Date(0));
const opt1 = { userIds: [userId1], date: now }; const opt1 = { userIds: [userId1], date: now };
return openpgp.generateKey(opt1).then(function(newKey) { return openpgp.generateKey(opt1).then(function(newKey) {
newKey = newKey.key; newKey = newKey.key;
expect(newKey.users[0].userId.userid).to.equal(userId1); expect(newKey.users[0].userId.userid).to.equal('test <a@b.com>');
expect(+newKey.getCreationTime()).to.equal(+now); expect(+newKey.getCreationTime()).to.equal(+now);
expect(+newKey.subKeys[0].getCreationTime()).to.equal(+now); expect(+newKey.subKeys[0].getCreationTime()).to.equal(+now);
expect(+newKey.subKeys[0].bindingSignatures[0].created).to.equal(+now); expect(+newKey.subKeys[0].bindingSignatures[0].created).to.equal(+now);
@ -2541,20 +2541,20 @@ function versionSpecificTests() {
return openpgp.reformatKey(opt2).then(function(refKey) { return openpgp.reformatKey(opt2).then(function(refKey) {
refKey = refKey.key; refKey = refKey.key;
expect(refKey.users.length).to.equal(1); expect(refKey.users.length).to.equal(1);
expect(refKey.users[0].userId.userid).to.equal(userId2); expect(refKey.users[0].userId.userid).to.equal('test <b@c.com>');
expect(+refKey.subKeys[0].bindingSignatures[0].created).to.equal(+before); expect(+refKey.subKeys[0].bindingSignatures[0].created).to.equal(+before);
}); });
}); });
}); });
it('Reformat key with no subkey without passphrase', async function() { it('Reformat key with no subkey without passphrase', async function() {
const userId = 'test1 <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const key = await openpgp.readArmoredKey(key_without_subkey); const key = await openpgp.readArmoredKey(key_without_subkey);
const opt = { privateKey: key, userIds: [userId] }; const opt = { privateKey: key, userIds: [userId] };
return openpgp.reformatKey(opt).then(function(newKey) { return openpgp.reformatKey(opt).then(function(newKey) {
newKey = newKey.key; newKey = newKey.key;
expect(newKey.users.length).to.equal(1); expect(newKey.users.length).to.equal(1);
expect(newKey.users[0].userId.userid).to.equal(userId); expect(newKey.users[0].userId.userid).to.equal('test <a@b.com>');
expect(newKey.isDecrypted()).to.be.true; expect(newKey.isDecrypted()).to.be.true;
return openpgp.sign({ message: openpgp.CleartextMessage.fromText('hello'), privateKeys: newKey, armor: true }).then(async function(signed) { return openpgp.sign({ message: openpgp.CleartextMessage.fromText('hello'), privateKeys: newKey, armor: true }).then(async function(signed) {
return openpgp.verify( return openpgp.verify(
@ -2570,9 +2570,9 @@ function versionSpecificTests() {
}); });
it('Reformat and encrypt key', function() { it('Reformat and encrypt key', function() {
const userId1 = 'test1 <a@b.com>'; const userId1 = { name: 'test1', email: 'a@b.com' };
const userId2 = 'test2 <b@c.com>'; const userId2 = { name: 'test2', email: 'b@c.com' };
const userId3 = 'test3 <c@d.com>'; const userId3 = { name: 'test3', email: 'c@d.com' };
const opt = { userIds: userId1 }; const opt = { userIds: userId1 };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function(key) {
key = key.key; key = key.key;
@ -2582,7 +2582,7 @@ function versionSpecificTests() {
return openpgp.reformatKey(opt).then(async function(newKey) { return openpgp.reformatKey(opt).then(async function(newKey) {
newKey = newKey.key; newKey = newKey.key;
expect(newKey.users.length).to.equal(2); expect(newKey.users.length).to.equal(2);
expect(newKey.users[0].userId.userid).to.equal(userId2); expect(newKey.users[0].userId.userid).to.equal('test2 <b@c.com>');
expect(newKey.isDecrypted()).to.be.false; expect(newKey.isDecrypted()).to.be.false;
await newKey.decrypt('123'); await newKey.decrypt('123');
expect(newKey.isDecrypted()).to.be.true; expect(newKey.isDecrypted()).to.be.true;
@ -2591,8 +2591,8 @@ function versionSpecificTests() {
}); });
it('Sign and encrypt with reformatted key', function() { it('Sign and encrypt with reformatted key', function() {
const userId1 = 'test1 <a@b.com>'; const userId1 = { name: 'test1', email: 'a@b.com' };
const userId2 = 'test2 <b@a.com>'; const userId2 = { name: 'test2', email: 'b@c.com' };
const opt = { userIds: userId1 }; const opt = { userIds: userId1 };
return openpgp.generateKey(opt).then(function(key) { return openpgp.generateKey(opt).then(function(key) {
key = key.key; key = key.key;
@ -2611,9 +2611,9 @@ function versionSpecificTests() {
}); });
it('Reject with user-friendly error when reformatting encrypted key', function() { it('Reject with user-friendly error when reformatting encrypted key', function() {
const opt = { userIds: 'test1 <a@b.com>', passphrase: '1234' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: '1234' };
return openpgp.generateKey(opt).then(function(original) { return openpgp.generateKey(opt).then(function(original) {
return openpgp.reformatKey({ privateKey: original.key, userIds: 'test2 <b@a.com>', passphrase: '1234' }).then(function() { return openpgp.reformatKey({ privateKey: original.key, userIds: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' }).then(function() {
throw new Error('reformatKey should result in error when key not decrypted'); throw new Error('reformatKey should result in error when key not decrypted');
}).catch(function(error) { }).catch(function(error) {
expect(error.message).to.equal('Error reformatting keypair: Key not decrypted'); expect(error.message).to.equal('Error reformatting keypair: Key not decrypted');
@ -2622,7 +2622,7 @@ function versionSpecificTests() {
}); });
it('Revoke generated key with revocation certificate', function() { it('Revoke generated key with revocation certificate', function() {
const opt = { userIds: 'test1 <a@b.com>', passphrase: '1234' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: '1234' };
return openpgp.generateKey(opt).then(function(original) { return openpgp.generateKey(opt).then(function(original) {
return openpgp.revokeKey({ key: original.key.toPublic(), revocationCertificate: original.revocationCertificate }).then(async function(revKey) { return openpgp.revokeKey({ key: original.key.toPublic(), revocationCertificate: original.revocationCertificate }).then(async function(revKey) {
revKey = revKey.publicKey; revKey = revKey.publicKey;
@ -2634,7 +2634,7 @@ function versionSpecificTests() {
}); });
it('Revoke generated key with private key', function() { it('Revoke generated key with private key', function() {
const opt = { userIds: 'test1 <a@b.com>', passphrase: '1234' }; const opt = { userIds: { name: 'test', email: 'a@b.com' }, passphrase: '1234' };
return openpgp.generateKey(opt).then(async function(original) { return openpgp.generateKey(opt).then(async function(original) {
await original.key.decrypt('1234'); await original.key.decrypt('1234');
return openpgp.revokeKey({ key: original.key, reasonForRevocation: { string: 'Testing key revocation' } }).then(async function(revKey) { return openpgp.revokeKey({ key: original.key, reasonForRevocation: { string: 'Testing key revocation' } }).then(async function(revKey) {
@ -2926,14 +2926,14 @@ module.exports = () => describe('Key', function() {
}); });
it('makeDummy() - the converted key can be parsed', async function() { it('makeDummy() - the converted key can be parsed', async function() {
const { key } = await openpgp.generateKey({ userIds: 'dummy <dummy@alice.com>' }); const { key } = await openpgp.generateKey({ userIds: { name: 'dummy', email: 'dummy@alice.com' } });
key.primaryKey.makeDummy(); key.primaryKey.makeDummy();
const parsedKeys = await openpgp.readArmoredKey(key.armor()); const parsedKeys = await openpgp.readArmoredKey(key.armor());
expect(parsedKeys).to.not.be.empty; expect(parsedKeys).to.not.be.empty;
}); });
it('makeDummy() - the converted key can be encrypted and decrypted', async function() { it('makeDummy() - the converted key can be encrypted and decrypted', async function() {
const { key } = await openpgp.generateKey({ userIds: 'dummy <dummy@alice.com>' }); const { key } = await openpgp.generateKey({ userIds: { name: 'dummy', email: 'dummy@alice.com' } });
const passphrase = 'passphrase'; const passphrase = 'passphrase';
key.primaryKey.makeDummy(); key.primaryKey.makeDummy();
expect(key.isDecrypted()).to.be.true; expect(key.isDecrypted()).to.be.true;
@ -2950,7 +2950,7 @@ module.exports = () => describe('Key', function() {
key.primaryKey.makeDummy(); key.primaryKey.makeDummy();
expect(key.primaryKey.isDummy()).to.be.true; expect(key.primaryKey.isDummy()).to.be.true;
await key.validate(); await key.validate();
await expect(openpgp.reformatKey({ privateKey: key, userIds: 'test2 <b@a.com>' })).to.be.rejectedWith(/Missing key parameters/); await expect(openpgp.reformatKey({ privateKey: key, userIds: { name: 'test', email: 'a@b.com' } })).to.be.rejectedWith(/Missing key parameters/);
}); });
it('makeDummy() - subkeys of the converted key can still sign', async function() { it('makeDummy() - subkeys of the converted key can still sign', async function() {
@ -3361,7 +3361,7 @@ VYGdb3eNlV8CfoEC
// Set first user to primary. We won't select this user, this is to test that. // Set first user to primary. We won't select this user, this is to test that.
privateKey.users[0].selfCertifications[0].isPrimaryUserID = true; 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. // 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>'); privateKey.users[0].userId = openpgp.UserIDPacket.fromObject({ name: 'Test User', email: 'b@c.com' });
// Set second user to prefer aes128. We will select this user. // Set second user to prefer aes128. We will select this user.
privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512]; privateKey.users[1].selfCertifications[0].preferredHashAlgorithms = [openpgp.enums.hash.sha512];
const signed = await openpgp.sign({ message: openpgp.Message.fromText('hello'), privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false }); const signed = await openpgp.sign({ message: openpgp.Message.fromText('hello'), privateKeys: privateKey, fromUserIds: { name: 'Test McTestington', email: 'test@example.com' }, armor: false });
@ -3487,7 +3487,7 @@ VYGdb3eNlV8CfoEC
}); });
it('Add a new default subkey to an rsaSign key', async function() { it('Add a new default subkey to an rsaSign key', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { type: 'rsa', rsaBits, userIds: [userId], subkeys: [] }; const opt = { type: 'rsa', rsaBits, userIds: [userId], subkeys: [] };
const { key } = await openpgp.generateKey(opt); const { key } = await openpgp.generateKey(opt);
expect(key.subKeys).to.have.length(0); expect(key.subKeys).to.have.length(0);
@ -3497,7 +3497,7 @@ VYGdb3eNlV8CfoEC
}); });
it('Add a new default subkey to an ecc key', async function() { it('Add a new default subkey to an ecc key', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { type: 'ecc', userIds: [userId], subkeys: [] }; const opt = { type: 'ecc', userIds: [userId], subkeys: [] };
const { key } = await openpgp.generateKey(opt); const { key } = await openpgp.generateKey(opt);
expect(key.subKeys).to.have.length(0); expect(key.subKeys).to.have.length(0);
@ -3537,8 +3537,8 @@ VYGdb3eNlV8CfoEC
await subKey.verify(importedPrivateKey.primaryKey); await subKey.verify(importedPrivateKey.primaryKey);
}); });
it('create and add a new eddsa subkey to a eddsa key', async function() { it('create and add a new ec subkey to a ec key', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] }; const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subKeys.length; const total = privateKey.subKeys.length;
@ -3562,7 +3562,7 @@ VYGdb3eNlV8CfoEC
}); });
it('create and add a new ecdsa subkey to a eddsa key', async function() { it('create and add a new ecdsa subkey to a eddsa key', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'ed25519', userIds: [userId], subkeys:[] }; const opt = { curve: 'ed25519', userIds: [userId], subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subKeys.length; const total = privateKey.subKeys.length;
@ -3596,7 +3596,7 @@ VYGdb3eNlV8CfoEC
}); });
it('create and add a new rsa subkey to a ecc key', async function() { it('create and add a new rsa subkey to a ecc key', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'ed25519', userIds: [userId], subkeys:[] }; const opt = { curve: 'ed25519', userIds: [userId], subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subKeys.length; const total = privateKey.subKeys.length;
@ -3625,7 +3625,7 @@ VYGdb3eNlV8CfoEC
}); });
it('sign/verify data with the new subkey correctly using curve25519', async function() { it('sign/verify data with the new subkey correctly using curve25519', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] }; const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const privateKey = (await openpgp.generateKey(opt)).key;
const total = privateKey.subKeys.length; const total = privateKey.subKeys.length;
@ -3650,7 +3650,7 @@ VYGdb3eNlV8CfoEC
}); });
it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() { it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() {
const userId = 'test <a@b.com>'; const userId = { name: 'test', email: 'a@b.com' };
const vData = 'the data to encrypted!'; const vData = 'the data to encrypted!';
const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] }; const opt = { curve: 'curve25519', userIds: [userId], subkeys:[] };
const privateKey = (await openpgp.generateKey(opt)).key; const privateKey = (await openpgp.generateKey(opt)).key;

View File

@ -558,7 +558,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
userIds: [{ name: {}, email: 'text@example.com' }] userIds: [{ name: {}, email: 'text@example.com' }]
}; };
const test = openpgp.generateKey(opt); const test = openpgp.generateKey(opt);
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/); await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
}); });
it('should fail for invalid user email address', async function() { it('should fail for invalid user email address', async function() {
@ -566,7 +566,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
userIds: [{ name: 'Test User', email: 'textexample.com' }] userIds: [{ name: 'Test User', email: 'textexample.com' }]
}; };
const test = openpgp.generateKey(opt); const test = openpgp.generateKey(opt);
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/); await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
}); });
it('should fail for invalid user email address', async function() { it('should fail for invalid user email address', async function() {
@ -574,61 +574,39 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
userIds: [{ name: 'Test User', email: 'text@examplecom' }] userIds: [{ name: 'Test User', email: 'text@examplecom' }]
}; };
const test = openpgp.generateKey(opt); const test = openpgp.generateKey(opt);
await expect(test).to.eventually.be.rejectedWith(/Invalid user id format/); await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
}); });
it('should fail for invalid string user id', async function() { it('should fail for string user ID', async function() {
const opt = {
userIds: ['Test User text@example.com>']
};
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', async function() {
const opt = {
userIds: 'Test User text@example.com>'
};
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() {
const opt = { const opt = {
userIds: 'Test User <text@example.com>' userIds: 'Test User <text@example.com>'
}; };
return openpgp.generateKey(opt); const test = openpgp.generateKey(opt);
await expect(test).to.eventually.be.rejectedWith(/Invalid user ID format/);
}); });
it('should work for valid string user id', function() { it('should work for valid single user ID object', function() {
const opt = {
userIds: ['Test User <text@example.com>']
};
return openpgp.generateKey(opt);
});
it('should work for valid single user id hash', function() {
const opt = { const opt = {
userIds: { name: 'Test User', email: 'text@example.com' } userIds: { name: 'Test User', email: 'text@example.com' }
}; };
return openpgp.generateKey(opt); return openpgp.generateKey(opt);
}); });
it('should work for valid single user id hash', function() { it('should work for array of user ID objects', function() {
const opt = { const opt = {
userIds: [{ name: 'Test User', email: 'text@example.com' }] userIds: [{ name: 'Test User', email: 'text@example.com' }]
}; };
return openpgp.generateKey(opt); return openpgp.generateKey(opt);
}); });
it('should work for an empty name', function() { it('should work for undefined name', function() {
const opt = { const opt = {
userIds: { email: 'text@example.com' } userIds: { email: 'text@example.com' }
}; };
return openpgp.generateKey(opt); return openpgp.generateKey(opt);
}); });
it('should work for an empty email address', function() { it('should work for an undefined email address', function() {
const opt = { const opt = {
userIds: { name: 'Test User' } userIds: { name: 'Test User' }
}; };
@ -2464,7 +2442,7 @@ amnR6g==
curves.forEach(curve => { curves.forEach(curve => {
it(`sign/verify with ${curve}`, async function() { it(`sign/verify with ${curve}`, async function() {
const plaintext = 'short message'; const plaintext = 'short message';
const key = (await openpgp.generateKey({ curve, userIds: 'Alice <info@alice.com>' })).key; const key = (await openpgp.generateKey({ curve, userIds: { name: 'Alice', email: 'info@alice.com' } })).key;
const signed = await openpgp.sign({ privateKeys:[key], message: openpgp.CleartextMessage.fromText(plaintext) }); const signed = await openpgp.sign({ privateKeys:[key], message: openpgp.CleartextMessage.fromText(plaintext) });
const verified = await openpgp.verify({ publicKeys:[key], message: await openpgp.readArmoredCleartextMessage(signed) }); const verified = await openpgp.verify({ publicKeys:[key], message: await openpgp.readArmoredCleartextMessage(signed) });
expect(verified.signatures[0].valid).to.be.true; expect(verified.signatures[0].valid).to.be.true;

View File

@ -142,22 +142,6 @@ module.exports = () => describe('Util unit tests', function() {
}); });
}); });
describe('parseUserID', function() {
it('should parse email address', function() {
const email = "TestName Test <test@example.com>";
const result = util.parseUserId(email);
expect(result.name).to.equal('TestName Test');
expect(result.email).to.equal('test@example.com');
});
it('should parse email address with @ in display name and comment', function() {
const email = "Test@Name Test (a comment) <test@example.com>";
const result = util.parseUserId(email);
expect(result.name).to.equal('Test@Name Test');
expect(result.email).to.equal('test@example.com');
expect(result.comment).to.equal('a comment');
});
});
describe("Misc.", function() { describe("Misc.", function() {
it('util.readNumber should not overflow until full range of uint32', function () { it('util.readNumber should not overflow until full range of uint32', function () {
const ints = [Math.pow(2, 20), Math.pow(2, 25), Math.pow(2, 30), Math.pow(2, 32) - 1]; const ints = [Math.pow(2, 20), Math.pow(2, 25), Math.pow(2, 30), Math.pow(2, 32) - 1];

View File

@ -10,7 +10,7 @@ const expect = chai.expect;
async function generateTestData() { async function generateTestData() {
const victimPrivKey = await key.generate({ const victimPrivKey = await key.generate({
userIds: ['Victim <victim@example.com>'], userIds: [{ name: 'Victim', email: 'victim@example.com' }],
type: 'rsa', type: 'rsa',
rsaBits: 1024, rsaBits: 1024,
subkeys: [{ subkeys: [{
@ -20,7 +20,7 @@ async function generateTestData() {
victimPrivKey.revocationSignatures = []; victimPrivKey.revocationSignatures = [];
const attackerPrivKey = await key.generate({ const attackerPrivKey = await key.generate({
userIds: ['Attacker <attacker@example.com>'], userIds: [{ name: 'Attacker', email: 'attacker@example.com' }],
type: 'rsa', type: 'rsa',
rsaBits: 1024, rsaBits: 1024,
subkeys: [], subkeys: [],