diff --git a/openpgp.d.ts b/openpgp.d.ts index 68451caef..18ad538c2 100644 --- a/openpgp.d.ts +++ b/openpgp.d.ts @@ -292,7 +292,7 @@ interface PartialConfig extends Partial {} /* ############## v5 PACKET #################### */ declare abstract class BasePacket { - public tag: enums.packet; + static readonly tag: enums.packet; public read(bytes: Uint8Array): void; public write(): Uint8Array; } @@ -314,14 +314,20 @@ declare abstract class BasePublicKeyPacket extends BasePacket { public getKeyID(): KeyID; public isDecrypted(): boolean; public publicParams: object; + // `isSubkey` is a dummy method to ensure that Subkey packets are not accepted as Key one, and vice versa. + // The key class hierarchy is already modelled to cover this, but the concrete key packet classes + // have compatible structure and TS can't detect the difference. + protected isSubkey(): boolean; } export class PublicKeyPacket extends BasePublicKeyPacket { - public tag: enums.packet.publicKey; + static readonly tag: enums.packet.publicKey; + protected isSubkey(): false; } export class PublicSubkeyPacket extends BasePublicKeyPacket { - public tag: enums.packet.publicSubkey; + static readonly tag: enums.packet.publicSubkey; + protected isSubkey(): true; } declare abstract class BaseSecretKeyPacket extends BasePublicKeyPacket { @@ -334,56 +340,78 @@ declare abstract class BaseSecretKeyPacket extends BasePublicKeyPacket { } export class SecretKeyPacket extends BaseSecretKeyPacket { - public tag: enums.packet.secretKey; + static readonly tag: enums.packet.secretKey; + protected isSubkey(): false; } export class SecretSubkeyPacket extends BaseSecretKeyPacket { - public tag: enums.packet.secretSubkey; + static readonly tag: enums.packet.secretSubkey; + protected isSubkey(): true; } export class CompressedDataPacket extends BasePacket { - public tag: enums.packet.compressedData; + static readonly tag: enums.packet.compressedData; + private compress(): void; + private decompress(): void; } export class SymEncryptedIntegrityProtectedDataPacket extends BasePacket { - public tag: enums.packet.symEncryptedIntegrityProtectedData; + static readonly tag: enums.packet.symEncryptedIntegrityProtectedData; } export class AEADEncryptedDataPacket extends BasePacket { - public tag: enums.packet.aeadEncryptedData; + static readonly tag: enums.packet.aeadEncryptedData; + private decrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array): void; + private encrypt(sessionKeyAlgorithm: string, sessionKey: Uint8Array, config?: Config): void; + private crypt(fn: Function, sessionKey: Uint8Array, data: MaybeStream): MaybeStream } export class PublicKeyEncryptedSessionKeyPaclet extends BasePacket { - public tag: enums.packet.publicKeyEncryptedSessionKey; + static readonly tag: enums.packet.publicKeyEncryptedSessionKey; + private decrypt(keyPacket: SecretKeyPacket): Promise; // throws on error + private encrypt(keyPacket: PublicKeyPacket): Promise; // throws on error } export class SymEncryptedSessionKey extends BasePacket { - public tag: enums.packet.symEncryptedSessionKey; + static readonly tag: enums.packet.symEncryptedSessionKey; + private decrypt(passphrase: string): Promise; + private encrypt(passphrase: string, config?: Config): Promise; } export class LiteralDataPacket extends BasePacket { - public tag: enums.packet.literalData; + static readonly tag: enums.packet.literalData; + private getText(clone?: boolean): MaybeStream; + private getBytes(clone?: boolean): MaybeStream; + private setText(text: MaybeStream, format?: DataPacketType); + private setBytes(bytes: MaybeStream, format?: DataPacketType); + private setFilename(filename: string); + private getFilename(): string; + private writeHeader(): Uint8Array; } export class SymmetricallyEncryptedDataPacket extends BasePacket { - public tag: enums.packet.symmetricallyEncryptedData; + static readonly tag: enums.packet.symmetricallyEncryptedData; + private decrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void; + private encrypt(sessionKeyAlgorithm: enums.symmetric, sessionKey: Uint8Array, config?: Config): void; } export class MarkerPacket extends BasePacket { - public tag: enums.packet.marker; + static readonly tag: enums.packet.marker; } export class UserAttributePacket extends BasePacket { - public tag: enums.packet.userAttribute; + static readonly tag: enums.packet.userAttribute; + private equals(packet: UserAttributePacket): boolean; } export class OnePassSignaturePacket extends BasePacket { - public tag: enums.packet.onePassSignature; + static readonly tag: enums.packet.onePassSignature; public correspondingSig?: Promise; + private verify: SignaturePacket['verify']; } export class UserIDPacket extends BasePacket { - public readonly tag: enums.packet.userID; + static readonly tag: enums.packet.userID; public readonly name: string; public readonly comment: string; public readonly email: string; @@ -392,7 +420,7 @@ export class UserIDPacket extends BasePacket { } export class SignaturePacket extends BasePacket { - public tag: enums.packet.signature; + static readonly tag: enums.packet.signature; public version: number; public signatureType: enums.signature | null; public hashAlgorithm: enums.hash | null; @@ -443,7 +471,7 @@ export class SignaturePacket extends BasePacket { } export class TrustPacket extends BasePacket { - public tag: enums.packet.trust; + static readonly tag: enums.packet.trust; } export type AnyPacket = BasePacket; @@ -453,24 +481,13 @@ export type AnyKeyPacket = BasePublicKeyPacket; type DataPacketType = 'utf8' | 'binary' | 'text' | 'mime'; -export class PacketList extends Array { - [index: number]: PACKET_TYPE; +export class PacketList extends Array { public length: number; public read(bytes: Uint8Array, allowedPackets?: object, config?: Config): void; public write(): Uint8Array; - public push(...packet: PACKET_TYPE[]): number; - public pop(): PACKET_TYPE; - public filter(callback: (packet: PACKET_TYPE, i: number, self: PacketList) => void): PacketList; - public filterByTag(...args: enums.packet[]): PacketList; - public forEach(callback: (packet: PACKET_TYPE, i: number, self: PacketList) => void): void; - public map(callback: (packet: PACKET_TYPE, i: number, self: PacketList) => RETURN_TYPE): PacketList; - // some() - // every() - // findPacket() - // indexOfTag() - // slice() - // concat() - // fromStructuredClone() + public filterByTag(...args: enums.packet[]): PacketList; + public indexOfTag(...tags: enums.packet[]): number[]; + public findPacket(tag: enums.packet): T | undefined; } /* ############## v5 STREAM #################### */ diff --git a/src/key/key.js b/src/key/key.js index 657bf064f..28289e70d 100644 --- a/src/key/key.js +++ b/src/key/key.js @@ -150,10 +150,10 @@ class Key { toPacketlist() { const packetlist = new PacketList(); packetlist.push(this.keyPacket); - packetlist.concat(this.revocationSignatures); - packetlist.concat(this.directSignatures); - this.users.map(user => packetlist.concat(user.toPacketlist())); - this.subKeys.map(subKey => packetlist.concat(subKey.toPacketlist())); + packetlist.push(...this.revocationSignatures); + packetlist.push(...this.directSignatures); + this.users.map(user => packetlist.push(...user.toPacketlist())); + this.subKeys.map(subKey => packetlist.push(...subKey.toPacketlist())); return packetlist; } diff --git a/src/key/subkey.js b/src/key/subkey.js index 52be0d859..a4ad6521e 100644 --- a/src/key/subkey.js +++ b/src/key/subkey.js @@ -34,8 +34,8 @@ class SubKey { toPacketlist() { const packetlist = new PacketList(); packetlist.push(this.keyPacket); - packetlist.concat(this.revocationSignatures); - packetlist.concat(this.bindingSignatures); + packetlist.push(...this.revocationSignatures); + packetlist.push(...this.bindingSignatures); return packetlist; } diff --git a/src/key/user.js b/src/key/user.js index 1bd14d43b..61c540e58 100644 --- a/src/key/user.js +++ b/src/key/user.js @@ -30,9 +30,9 @@ class User { toPacketlist() { const packetlist = new PacketList(); packetlist.push(this.userID || this.userAttribute); - packetlist.concat(this.revocationSignatures); - packetlist.concat(this.selfCertifications); - packetlist.concat(this.otherCertifications); + packetlist.push(...this.revocationSignatures); + packetlist.push(...this.selfCertifications); + packetlist.push(...this.otherCertifications); return packetlist; } diff --git a/src/message.js b/src/message.js index 9b29efd0a..f92bdc324 100644 --- a/src/message.js +++ b/src/message.js @@ -170,7 +170,7 @@ export class Message { let exception; if (passwords) { const symESKeyPacketlist = this.packets.filterByTag(enums.packet.symEncryptedSessionKey); - if (!symESKeyPacketlist) { + if (symESKeyPacketlist.length === 0) { throw new Error('No symmetrically encrypted session key packet found.'); } await Promise.all(passwords.map(async function(password, i) { @@ -192,7 +192,7 @@ export class Message { })); } else if (privateKeys) { const pkESKeyPacketlist = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey); - if (!pkESKeyPacketlist) { + if (pkESKeyPacketlist.length === 0) { throw new Error('No public key encrypted session key packet found.'); } await Promise.all(pkESKeyPacketlist.map(async function(keyPacket) { @@ -385,7 +385,7 @@ export class Message { delete pkESKeyPacket.sessionKey; // delete plaintext session key after encryption return pkESKeyPacket; })); - packetlist.concat(results); + packetlist.push(...results); } if (passwords) { const testDecrypt = async function(keyPacket, password) { @@ -420,7 +420,7 @@ export class Message { }; const results = await Promise.all(passwords.map(pwd => encryptPassword(sessionKey, algorithm, aeadAlgorithm, pwd))); - packetlist.concat(results); + packetlist.push(...results); } return new Message(packetlist); @@ -487,7 +487,7 @@ export class Message { }); packetlist.push(literalDataPacket); - packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, false, config)); + packetlist.push(...(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, false, config))); return new Message(packetlist); } @@ -551,7 +551,7 @@ export class Message { throw new Error('Can only verify message with one literal data packet.'); } if (stream.isArrayStream(msg.packets.stream)) { - msg.packets.concat(await stream.readToEnd(msg.packets.stream, _ => _)); + msg.packets.push(...await stream.readToEnd(msg.packets.stream, _ => _ || [])); } const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse(); const signatureList = msg.packets.filterByTag(enums.packet.signature); @@ -686,7 +686,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig if (signature) { const existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature); - packetlist.concat(existingSigPacketlist); + packetlist.push(...existingSigPacketlist); } return packetlist; } @@ -752,7 +752,7 @@ async function createVerificationObject(signature, literalDataList, keys, date = signature: (async () => { const sig = await signaturePacket; const packetlist = new PacketList(); - packetlist.push(sig); + sig && packetlist.push(sig); return new Signature(packetlist); })() }; diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js index 0cd0464cb..aa9c86eb5 100644 --- a/src/packet/aead_encrypted_data.js +++ b/src/packet/aead_encrypted_data.js @@ -25,6 +25,7 @@ import LiteralDataPacket from './literal_data'; import CompressedDataPacket from './compressed_data'; import OnePassSignaturePacket from './one_pass_signature'; import SignaturePacket from './signature'; +import PacketList from './packetlist'; // An AEAD-encrypted Data packet can contain the following packet types const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([ @@ -93,6 +94,7 @@ class AEADEncryptedDataPacket { * @async */ async decrypt(sessionKeyAlgorithm, key) { + this.packets = new PacketList(); await this.packets.read(await this.crypt('decrypt', key, stream.clone(this.encrypted)), allowedPackets); } diff --git a/src/packet/compressed_data.js b/src/packet/compressed_data.js index a3413a414..cda81e97e 100644 --- a/src/packet/compressed_data.js +++ b/src/packet/compressed_data.js @@ -27,6 +27,7 @@ import defaultConfig from '../config'; import LiteralDataPacket from './literal_data'; import OnePassSignaturePacket from './one_pass_signature'; import SignaturePacket from './signature'; +import PacketList from './packetlist'; // A Compressed Data packet can contain the following packet types const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([ @@ -116,6 +117,7 @@ class CompressedDataPacket { throw new Error(this.algorithm + ' decompression not supported'); } + this.packets = new PacketList(); await this.packets.read(decompress_fns[this.algorithm](this.compressed), allowedPackets); } diff --git a/src/packet/marker.js b/src/packet/marker.js index d55df6d17..1ee18fbf7 100644 --- a/src/packet/marker.js +++ b/src/packet/marker.js @@ -28,7 +28,13 @@ import enums from '../enums'; * tag. With PGP 5.x, this packet has been reassigned and is reserved for use as * the Marker packet. * - * Such a packet MUST be ignored when received. + * The body of this packet consists of: + * The three octets 0x50, 0x47, 0x50 (which spell "PGP" in UTF-8). + * + * Such a packet MUST be ignored when received. It may be placed at the + * beginning of a message that uses features not available in PGP + * version 2.6 in order to cause that version to report that newer + * software is necessary to process the message. */ class MarkerPacket { static get tag() { @@ -36,15 +42,9 @@ class MarkerPacket { } /** - * Parsing function for a literal data packet (tag 10). - * - * @param {String} input - Payload of a tag 10 packet - * @param {Integer} position - * Position to start reading from the input string - * @param {Integer} len - * Length of the packet or the remaining length of - * input at position - * @returns {MarkerPacket} Object representation. + * Parsing function for a marker data packet (tag 10). + * @param {Uint8Array} bytes - Payload of a tag 10 packet + * @returns {Boolean} whether the packet payload contains "PGP" */ read(bytes) { if (bytes[0] === 0x50 && // P @@ -52,9 +52,13 @@ class MarkerPacket { bytes[2] === 0x50) { // P return true; } - // marker packet does not contain "PGP" return false; } + + // eslint-disable-next-line class-methods-use-this + write() { + return new Uint8Array([0x50, 0x47, 0x50]); + } } export default MarkerPacket; diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index 742c17147..1be3fa697 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -127,30 +127,17 @@ class PacketList extends Array { } /** - * Adds a packet to the list. This is the only supported method of doing so; - * writing to packetlist[i] directly will result in an error. - * @param {Object} packet - Packet to push + * Creates a new PacketList with all packets matching the given tag(s) + * @param {...module:enums.packet} tags - packet tags to look for + * @returns {PacketList} */ - push(packet) { - if (!packet) { - return; - } - - packet.packets = packet.packets || new PacketList(); - - super.push(packet); - } - - /** - * Creates a new PacketList with all packets from the given types - */ - filterByTag(...args) { + filterByTag(...tags) { const filtered = new PacketList(); const handle = tag => packetType => tag === packetType; for (let i = 0; i < this.length; i++) { - if (args.some(handle(this[i].constructor.tag))) { + if (tags.some(handle(this[i].constructor.tag))) { filtered.push(this[i]); } } @@ -159,42 +146,32 @@ class PacketList extends Array { } /** - * Traverses packet tree and returns first matching packet - * @param {module:enums.packet} type - The packet type + * Traverses packet list and returns first packet with matching tag + * @param {module:enums.packet} tag - The packet tag * @returns {Packet|undefined} */ - findPacket(type) { - return this.find(packet => packet.constructor.tag === type); + findPacket(tag) { + return this.find(packet => packet.constructor.tag === tag); } /** - * Returns array of found indices by tag + * Find indices of packets with the given tag(s) + * @param {...module:enums.packet} tags - packet tags to look for + * @returns {Integer[]} packet indices */ - indexOfTag(...args) { + indexOfTag(...tags) { const tagIndex = []; const that = this; const handle = tag => packetType => tag === packetType; for (let i = 0; i < this.length; i++) { - if (args.some(handle(that[i].constructor.tag))) { + if (tags.some(handle(that[i].constructor.tag))) { tagIndex.push(i); } } return tagIndex; } - - /** - * Concatenates packetlist or array of packets - */ - concat(packetlist) { - if (packetlist) { - for (let i = 0; i < packetlist.length; i++) { - this.push(packetlist[i]); - } - } - return this; - } } export default PacketList; diff --git a/src/packet/sym_encrypted_integrity_protected_data.js b/src/packet/sym_encrypted_integrity_protected_data.js index 15deffbcf..d49e1642d 100644 --- a/src/packet/sym_encrypted_integrity_protected_data.js +++ b/src/packet/sym_encrypted_integrity_protected_data.js @@ -25,6 +25,7 @@ import LiteralDataPacket from './literal_data'; import CompressedDataPacket from './compressed_data'; import OnePassSignaturePacket from './one_pass_signature'; import SignaturePacket from './signature'; +import PacketList from './packetlist'; // A SEIP packet can contain the following packet types const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([ @@ -53,15 +54,7 @@ class SymEncryptedIntegrityProtectedDataPacket { constructor() { this.version = VERSION; - /** The encrypted payload. */ - this.encrypted = null; // string - /** - * If after decrypting the packet this is set to true, - * a modification has been detected and thus the contents - * should be discarded. - * @type {Boolean} - */ - this.modification = false; + this.encrypted = null; this.packets = null; } @@ -138,6 +131,7 @@ class SymEncryptedIntegrityProtectedDataPacket { if (!util.isStream(encrypted) || !config.allowUnauthenticatedStream) { packetbytes = await stream.readToEnd(packetbytes); } + this.packets = new PacketList(); await this.packets.read(packetbytes, allowedPackets); return true; } diff --git a/src/packet/symmetrically_encrypted_data.js b/src/packet/symmetrically_encrypted_data.js index b532a3465..e7711e781 100644 --- a/src/packet/symmetrically_encrypted_data.js +++ b/src/packet/symmetrically_encrypted_data.js @@ -25,6 +25,7 @@ import LiteralDataPacket from './literal_data'; import CompressedDataPacket from './compressed_data'; import OnePassSignaturePacket from './one_pass_signature'; import SignaturePacket from './signature'; +import PacketList from './packetlist'; // A SE packet can contain the following packet types const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([ @@ -91,6 +92,7 @@ class SymmetricallyEncryptedDataPacket { encrypted.subarray(2, crypto.cipher[sessionKeyAlgorithm].blockSize + 2) ); + this.packets = new PacketList(); await this.packets.read(decrypted, allowedPackets); } diff --git a/src/packet/trust.js b/src/packet/trust.js index b1aeec4f4..8d1bc93b4 100644 --- a/src/packet/trust.js +++ b/src/packet/trust.js @@ -28,6 +28,11 @@ class TrustPacket { * @param {String} byptes - Payload of a tag 12 packet */ read() {} // TODO + + // eslint-disable-next-line class-methods-use-this + write() { + throw new Error('Trust packets are not supported'); + } } export default TrustPacket; diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 58998227b..625b96be3 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -2722,7 +2722,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { }; return openpgp.sign(signOpt).then(async function (signed) { const message = await openpgp.readMessage({ binaryMessage: signed }); - message.packets.concat(await openpgp.stream.readToEnd(message.packets.stream, _ => _)); + message.packets.push(...await openpgp.stream.readToEnd(message.packets.stream, _ => _)); const packets = new openpgp.PacketList(); packets.push(message.packets.findPacket(openpgp.enums.packet.signature)); packets.push(message.packets.findPacket(openpgp.enums.packet.literalData)); @@ -2762,7 +2762,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { return openpgp.sign(signOpt).then(async function (signed) { expect(openpgp.stream.isStream(signed)).to.equal(global.ReadableStream ? 'web' : 'node'); const message = await openpgp.readMessage({ binaryMessage: signed }); - message.packets.concat(await openpgp.stream.readToEnd(message.packets.stream, _ => _)); + message.packets.push(...await openpgp.stream.readToEnd(message.packets.stream, _ => _)); const packets = new openpgp.PacketList(); packets.push(message.packets.findPacket(openpgp.enums.packet.signature)); packets.push(message.packets.findPacket(openpgp.enums.packet.literalData)); diff --git a/test/general/packet.js b/test/general/packet.js index 6f3cdd16d..dd1785828 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -81,8 +81,9 @@ module.exports = () => describe("Packet", function() { try { const enc = new openpgp.SymmetricallyEncryptedDataPacket(); - message.push(enc); + enc.packets = new openpgp.PacketList(); enc.packets.push(literal); + message.push(enc); const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); const algo = 'aes256'; @@ -112,8 +113,9 @@ module.exports = () => describe("Packet", function() { literal.setText(testText); const enc = new openpgp.SymmetricallyEncryptedDataPacket(); + enc.packets = new openpgp.PacketList(); + enc.packets.push(literal); message.push(enc); - await enc.packets.push(literal); const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); const algo = 'aes256'; @@ -135,11 +137,12 @@ module.exports = () => describe("Packet", function() { const literal = new openpgp.LiteralDataPacket(); const enc = new openpgp.SymEncryptedIntegrityProtectedDataPacket(); + enc.packets = new openpgp.PacketList(); + enc.packets.push(literal); const msg = new openpgp.PacketList(); - msg.push(enc); + literal.setText(testText); - enc.packets.push(literal); await enc.encrypt(algo, key, undefined, openpgp.config); const msg2 = new openpgp.PacketList(); @@ -158,12 +161,12 @@ module.exports = () => describe("Packet", function() { const algo = 'aes256'; const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); + literal.setText(testText); const enc = new openpgp.AEADEncryptedDataPacket(); + enc.packets = new openpgp.PacketList(); + enc.packets.push(literal); const msg = new openpgp.PacketList(); - msg.push(enc); - literal.setText(testText); - enc.packets.push(literal); const msg2 = new openpgp.PacketList(); @@ -210,13 +213,13 @@ module.exports = () => describe("Packet", function() { const algo = 'aes256'; const literal = new openpgp.LiteralDataPacket(); + literal.setText(testText); const enc = new openpgp.AEADEncryptedDataPacket(); - const msg = new openpgp.PacketList(); enc.aeadAlgorithm = 'experimentalGCM'; - - msg.push(enc); - literal.setText(testText); + enc.packets = new openpgp.PacketList(); enc.packets.push(literal); + const msg = new openpgp.PacketList(); + msg.push(enc); const msg2 = new openpgp.PacketList(); @@ -252,13 +255,13 @@ module.exports = () => describe("Packet", function() { const algo = 'aes128'; const literal = new openpgp.LiteralDataPacket(0); - const enc = new openpgp.AEADEncryptedDataPacket(); - const msg = new openpgp.PacketList(); - - msg.push(enc); literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); literal.filename = ''; + const enc = new openpgp.AEADEncryptedDataPacket(); + enc.packets = new openpgp.PacketList(); enc.packets.push(literal); + const msg = new openpgp.PacketList(); + msg.push(enc); const msg2 = new openpgp.PacketList(); @@ -446,8 +449,11 @@ module.exports = () => describe("Packet", function() { const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); + literal.setText(testText); const skesk = new openpgp.SymEncryptedSessionKeyPacket(); const seip = new openpgp.SymEncryptedIntegrityProtectedDataPacket(); + seip.packets = new openpgp.PacketList(); + seip.packets.push(literal); const msg = new openpgp.PacketList(); msg.push(skesk); @@ -457,9 +463,6 @@ module.exports = () => describe("Packet", function() { await skesk.encrypt(passphrase, openpgp.config); const key = skesk.sessionKey; - - literal.setText(testText); - seip.packets.push(literal); await seip.encrypt(algo, key, undefined, openpgp.config); const msg2 = new openpgp.PacketList(); @@ -485,10 +488,12 @@ module.exports = () => describe("Packet", function() { const testText = input.createSomeMessage(); const literal = new openpgp.LiteralDataPacket(); + literal.setText(testText); const skesk = new openpgp.SymEncryptedSessionKeyPacket(); const aeadEnc = new openpgp.AEADEncryptedDataPacket(); + aeadEnc.packets = new openpgp.PacketList(); + aeadEnc.packets.push(literal); const msg = new openpgp.PacketList(); - msg.push(skesk); msg.push(aeadEnc); @@ -496,9 +501,6 @@ module.exports = () => describe("Packet", function() { await skesk.encrypt(passphrase, openpgp.config); const key = skesk.sessionKey; - - literal.setText(testText); - aeadEnc.packets.push(literal); await aeadEnc.encrypt(algo, key, undefined, openpgp.config); const msg2 = new openpgp.PacketList(); @@ -556,21 +558,20 @@ module.exports = () => describe("Packet", function() { const algo = 'aes128'; const literal = new openpgp.LiteralDataPacket(0); + literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); + literal.filename = ''; const skesk = new openpgp.SymEncryptedSessionKeyPacket(); + skesk.sessionKeyAlgorithm = algo; const encData = new openpgp.AEADEncryptedDataPacket(); + encData.packets = new openpgp.PacketList(); + encData.packets.push(literal); const msg = new openpgp.PacketList(); - msg.push(skesk); msg.push(encData); - skesk.sessionKeyAlgorithm = algo; await skesk.encrypt(passphrase, openpgp.config); const key = skesk.sessionKey; - - literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); - literal.filename = ''; - encData.packets.push(literal); await encData.encrypt(algo, key, undefined, openpgp.config); const data = msg.write(); @@ -634,22 +635,21 @@ module.exports = () => describe("Packet", function() { const algo = 'aes128'; const literal = new openpgp.LiteralDataPacket(0); + literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); + literal.filename = ''; const key_enc = new openpgp.SymEncryptedSessionKeyPacket(); + key_enc.sessionKeyAlgorithm = algo; const enc = new openpgp.AEADEncryptedDataPacket(); - const msg = new openpgp.PacketList(); + enc.packets = new openpgp.PacketList(); + enc.packets.push(literal); enc.aeadAlgorithm = key_enc.aeadAlgorithm = 'ocb'; - + const msg = new openpgp.PacketList(); msg.push(key_enc); msg.push(enc); - key_enc.sessionKeyAlgorithm = algo; await key_enc.encrypt(passphrase, openpgp.config); const key = key_enc.sessionKey; - - literal.setBytes(util.stringToUint8Array('Hello, world!\n'), openpgp.enums.literal.binary); - literal.filename = ''; - enc.packets.push(literal); await enc.encrypt(algo, key, undefined, openpgp.config); const data = msg.write(); @@ -747,7 +747,7 @@ module.exports = () => describe("Packet", function() { await encData.decrypt(pkesk.sessionKeyAlgorithm, pkesk.sessionKey); const payload = encData.packets[0].packets; - payload.concat(await openpgp.stream.readToEnd(payload.stream, arr => arr)); + payload.push(...await openpgp.stream.readToEnd(payload.stream, arr => arr)); const literal = payload[1]; const signature = payload[2]; @@ -942,7 +942,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ const signed2 = new openpgp.PacketList(); await signed2.read(raw, allAllowedPackets); - signed2.concat(await openpgp.stream.readToEnd(signed2.stream, arr => arr)); + signed2.push(...await openpgp.stream.readToEnd(signed2.stream, arr => arr)); await Promise.all([ signed2[1].verify(key, openpgp.enums.signature.text, signed2[0]), diff --git a/test/security/subkey_trust.js b/test/security/subkey_trust.js index 387a6cc94..d32a378a1 100644 --- a/test/security/subkey_trust.js +++ b/test/security/subkey_trust.js @@ -56,7 +56,7 @@ async function testSubkeyTrust() { fakeBindingSignature.keyFlags = [enums.keyFlags.signData]; await fakeBindingSignature.sign(attackerPrivKey.keyPacket, dataToSign); const newList = new PacketList(); - newList.concat([ + newList.push(...[ pktPrivAttacker[0], // attacker private key pktPrivAttacker[1], // attacker user pktPrivAttacker[2], // attacker self signature diff --git a/test/security/unsigned_subpackets.js b/test/security/unsigned_subpackets.js index 2029ea6fe..66c091433 100644 --- a/test/security/unsigned_subpackets.js +++ b/test/security/unsigned_subpackets.js @@ -81,7 +81,7 @@ async function makeKeyValid() { pusersig.readSubPackets(fake.writeHashedSubPackets(), false); // reconstruct the modified key const newlist = new PacketList(); - newlist.concat([pubkey, puser, pusersig]); + newlist.push(...[pubkey, puser, pusersig]); let modifiedkey = new Key(newlist); // re-read the message to eliminate any // behaviour due to cached values. diff --git a/test/typescript/definitions.ts b/test/typescript/definitions.ts index 60db7c601..4e9f42b9d 100644 --- a/test/typescript/definitions.ts +++ b/test/typescript/definitions.ts @@ -6,9 +6,13 @@ * - if it fails to run, edit this file to match the actual library API, then edit the definitions file (openpgp.d.ts) accordingly. */ -import { generateKey, readKey, readKeys, Key, readMessage, createMessage, Message, createCleartextMessage, encrypt, decrypt, sign, verify, config } from '../..'; - import { expect } from 'chai'; +import { + generateKey, readKey, readKeys, Key, + readMessage, createMessage, Message, createCleartextMessage, + encrypt, decrypt, sign, verify, config, enums, + LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket +} from '../..'; (async () => { @@ -78,6 +82,34 @@ import { expect } from 'chai'; const verifiedBinaryData: Uint8Array = verifiedBinary.data; expect(verifiedBinaryData).to.deep.equal(binary); + // Generic packetlist + const packets = new PacketList(); + expect(packets.push()).to.equal(0); + expect(packets.push(new LiteralDataPacket())).to.equal(1); + packets.map(packet => packet.write); + // @ts-expect-error for unsafe downcasting + packets.map((packet: LiteralDataPacket) => packet.getText()); + // @ts-expect-error for non-packet element + try { new PacketList().push(1); } catch (e) {} + + + // Packetlist of specific type + const literalPackets = new PacketList(); + literalPackets.push(new LiteralDataPacket()); + literalPackets[0].write(); + literalPackets.map((packet: LiteralDataPacket) => packet); + packets.push(...literalPackets); + // @ts-expect-error for incompatible packetlist type + literalPackets.push(...packets); + // @ts-expect-error for incompatible packet type + new PacketList().push(new CompressedDataPacket()); + // @ts-expect-error for incompatible packet type + new PacketList().push(new PublicSubkeyPacket()); + // @ts-expect-error for incompatible packet type + new PacketList().push(new SecretSubkeyPacket()); + + expect(LiteralDataPacket.tag).to.equal(enums.packet.literalData); + // // Detached - sign cleartext message (armored) // import { Message, sign } from 'openpgp'; // const message = await createMessage({ text: util.removeTrailingSpaces(text) });