Drop support for native Node Readable stream: require passing Node Web Streams

Utils to convert from and to Web Streams in Node are available from v17,
see https://nodejs.org/api/stream.html#streamreadabletowebstreamreadable-options .

Previously, we automatically converted between Node native streams and custom, Web-like Readable streams.
This led to occasional issues.
This commit is contained in:
larabr 2024-01-16 17:44:29 +01:00
parent 591b9399a8
commit 790d8e20db
9 changed files with 96 additions and 105 deletions

22
openpgp.d.ts vendored
View File

@ -7,7 +7,7 @@
* - Errietta Kostala <https://github.com/errietta> * - Errietta Kostala <https://github.com/errietta>
*/ */
import type { WebStream as GenericWebStream, NodeStream as GenericNodeStream } from '@openpgp/web-stream-tools'; import type { WebStream as GenericWebStream, NodeWebStream as GenericNodeWebStream } from '@openpgp/web-stream-tools';
/* ############## v5 KEY #################### */ /* ############## v5 KEY #################### */
// The Key and PublicKey types can be used interchangably since TS cannot detect the difference, as they have the same class properties. // The Key and PublicKey types can be used interchangably since TS cannot detect the difference, as they have the same class properties.
@ -191,24 +191,24 @@ export function createMessage<T extends MaybeStream<Uint8Array>>(options: { bina
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format?: 'armored' }): Promise< export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format?: 'armored' }): Promise<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeWebStream<infer X> ? NodeWebStream<string> :
string string
>; >;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'binary' }): Promise< export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'binary' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> : T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> : T extends NodeWebStream<infer X> ? NodeWebStream<Uint8Array> :
Uint8Array Uint8Array
>; >;
export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>; export function encrypt<T extends MaybeStream<Data>>(options: EncryptOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format?: 'armored' }): Promise< export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format?: 'armored' }): Promise<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeWebStream<infer X> ? NodeWebStream<string> :
string string
>; >;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'binary' }): Promise< export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'binary' }): Promise<
T extends WebStream<infer X> ? WebStream<Uint8Array> : T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> : T extends NodeWebStream<infer X> ? NodeWebStream<Uint8Array> :
Uint8Array Uint8Array
>; >;
export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>; export function sign<T extends MaybeStream<Data>>(options: SignOptions & { message: Message<T>, format: 'object' }): Promise<Message<T>>;
@ -218,25 +218,25 @@ export function sign(options: SignOptions & { message: CleartextMessage, format:
export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T>, format: 'binary' }): Promise<DecryptMessageResult & { export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T>, format: 'binary' }): Promise<DecryptMessageResult & {
data: data:
T extends WebStream<infer X> ? WebStream<Uint8Array> : T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> : T extends NodeWebStream<infer X> ? NodeWebStream<Uint8Array> :
Uint8Array Uint8Array
}>; }>;
export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T> }): Promise<DecryptMessageResult & { export function decrypt<T extends MaybeStream<Data>>(options: DecryptOptions & { message: Message<T> }): Promise<DecryptMessageResult & {
data: data:
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeWebStream<infer X> ? NodeWebStream<string> :
string string
}>; }>;
export function verify(options: VerifyOptions & { message: CleartextMessage, format?: 'utf8' }): Promise<VerifyMessageResult<string>>; export function verify(options: VerifyOptions & { message: CleartextMessage, format?: 'utf8' }): Promise<VerifyMessageResult<string>>;
export function verify<T extends MaybeStream<Data>>(options: VerifyOptions & { message: Message<T>, format: 'binary' }): Promise<VerifyMessageResult< export function verify<T extends MaybeStream<Data>>(options: VerifyOptions & { message: Message<T>, format: 'binary' }): Promise<VerifyMessageResult<
T extends WebStream<infer X> ? WebStream<Uint8Array> : T extends WebStream<infer X> ? WebStream<Uint8Array> :
T extends NodeStream<infer X> ? NodeStream<Uint8Array> : T extends NodeWebStream<infer X> ? NodeWebStream<Uint8Array> :
Uint8Array Uint8Array
>>; >>;
export function verify<T extends MaybeStream<Data>>(options: VerifyOptions & { message: Message<T> }): Promise<VerifyMessageResult< export function verify<T extends MaybeStream<Data>>(options: VerifyOptions & { message: Message<T> }): Promise<VerifyMessageResult<
T extends WebStream<infer X> ? WebStream<string> : T extends WebStream<infer X> ? WebStream<string> :
T extends NodeStream<infer X> ? NodeStream<string> : T extends NodeWebStream<infer X> ? NodeWebStream<string> :
string string
>>; >>;
@ -565,8 +565,8 @@ export class PacketList<T extends AnyPacket> extends Array<T> {
type Data = Uint8Array | string; type Data = Uint8Array | string;
export interface WebStream<T extends Data> extends GenericWebStream<T> {} export interface WebStream<T extends Data> extends GenericWebStream<T> {}
export interface NodeStream<T extends Data> extends GenericNodeStream<T> {} export interface NodeWebStream<T extends Data> extends GenericNodeWebStream<T> {}
export type Stream<T extends Data> = WebStream<T> | NodeStream<T>; export type Stream<T extends Data> = WebStream<T> | NodeWebStream<T>;
export type MaybeStream<T extends Data> = T | Stream<T>; export type MaybeStream<T extends Data> = T | Stream<T>;
/* ############## v5 GENERAL #################### */ /* ############## v5 GENERAL #################### */

81
package-lock.json generated
View File

@ -18,10 +18,10 @@
"@openpgp/noble-hashes": "^1.3.3-0", "@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git", "@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.4-1", "@openpgp/tweetnacl": "^1.0.4-1",
"@openpgp/web-stream-tools": "^0.0.14", "@openpgp/web-stream-tools": "~0.1.1",
"@rollup/plugin-alias": "^5.0.0", "@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-wasm": "^6.1.2", "@rollup/plugin-wasm": "^6.1.2",
@ -56,7 +56,7 @@
"web-streams-polyfill": "^3.2.0" "web-streams-polyfill": "^3.2.0"
}, },
"engines": { "engines": {
"node": ">= 16.0.0" "node": ">= 16.5.0"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -630,10 +630,13 @@
"dev": true "dev": true
}, },
"node_modules/@openpgp/web-stream-tools": { "node_modules/@openpgp/web-stream-tools": {
"version": "0.0.14", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.14.tgz", "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.1.1.tgz",
"integrity": "sha512-6btCNVf6YSsmlyIS7yw+IbzXeXCEcJxeSpxvSxkDuZj9B/ekt4fXkZj4oOaIxG4SKTftIK1svnlVroJ1cCMT4g==", "integrity": "sha512-1WkV+z78S8DJNlUiCPxSjsna6gfAGCVuepL2KUDlBztXzhvplwWr4lAvsWcYzFkHykaFoCSOV9ssiRRq7QzydQ==",
"dev": true, "dev": true,
"engines": {
"node": ">= 16.5.0"
},
"peerDependencies": { "peerDependencies": {
"typescript": ">=4.2" "typescript": ">=4.2"
}, },
@ -729,9 +732,9 @@
} }
}, },
"node_modules/@rollup/plugin-node-resolve": { "node_modules/@rollup/plugin-node-resolve": {
"version": "15.0.2", "version": "15.2.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
"integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==", "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@rollup/pluginutils": "^5.0.1", "@rollup/pluginutils": "^5.0.1",
@ -745,7 +748,7 @@
"node": ">=14.0.0" "node": ">=14.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"rollup": "^2.78.0||^3.0.0" "rollup": "^2.78.0||^3.0.0||^4.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"rollup": { "rollup": {
@ -1004,10 +1007,13 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "13.13.2", "version": "20.11.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.4.tgz",
"integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==", "integrity": "sha512-6I0fMH8Aoy2lOejL3s4LhyIYX34DPwY8bl5xlNjBvUEk8OHrcuzsFt+Ied4LvJihbtXPM+8zUqdydfIti86v9g==",
"dev": true "dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
}, },
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {
"version": "2.4.3", "version": "2.4.3",
@ -3145,9 +3151,9 @@
"dev": true "dev": true
}, },
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.2", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
@ -6544,6 +6550,12 @@
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
"dev": true "dev": true
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/union": { "node_modules/union": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
@ -7247,9 +7259,9 @@
"dev": true "dev": true
}, },
"@openpgp/web-stream-tools": { "@openpgp/web-stream-tools": {
"version": "0.0.14", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.0.14.tgz", "resolved": "https://registry.npmjs.org/@openpgp/web-stream-tools/-/web-stream-tools-0.1.1.tgz",
"integrity": "sha512-6btCNVf6YSsmlyIS7yw+IbzXeXCEcJxeSpxvSxkDuZj9B/ekt4fXkZj4oOaIxG4SKTftIK1svnlVroJ1cCMT4g==", "integrity": "sha512-1WkV+z78S8DJNlUiCPxSjsna6gfAGCVuepL2KUDlBztXzhvplwWr4lAvsWcYzFkHykaFoCSOV9ssiRRq7QzydQ==",
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
@ -7310,9 +7322,9 @@
} }
}, },
"@rollup/plugin-node-resolve": { "@rollup/plugin-node-resolve": {
"version": "15.0.2", "version": "15.2.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
"integrity": "sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==", "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@rollup/pluginutils": "^5.0.1", "@rollup/pluginutils": "^5.0.1",
@ -7531,10 +7543,13 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "13.13.2", "version": "20.11.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.4.tgz",
"integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==", "integrity": "sha512-6I0fMH8Aoy2lOejL3s4LhyIYX34DPwY8bl5xlNjBvUEk8OHrcuzsFt+Ied4LvJihbtXPM+8zUqdydfIti86v9g==",
"dev": true "dev": true,
"requires": {
"undici-types": "~5.26.4"
}
}, },
"@types/normalize-package-data": { "@types/normalize-package-data": {
"version": "2.4.3", "version": "2.4.3",
@ -9186,9 +9201,9 @@
"dev": true "dev": true
}, },
"fsevents": { "fsevents": {
"version": "2.3.2", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
@ -11753,6 +11768,12 @@
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
"dev": true "dev": true
}, },
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"union": { "union": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",

View File

@ -5,7 +5,7 @@
"license": "LGPL-3.0+", "license": "LGPL-3.0+",
"homepage": "https://openpgpjs.org/", "homepage": "https://openpgpjs.org/",
"engines": { "engines": {
"node": ">= 16.0.0" "node": ">= 16.5.0"
}, },
"keywords": [ "keywords": [
"crypto", "crypto",
@ -68,10 +68,10 @@
"@openpgp/noble-hashes": "^1.3.3-0", "@openpgp/noble-hashes": "^1.3.3-0",
"@openpgp/seek-bzip": "^1.0.5-git", "@openpgp/seek-bzip": "^1.0.5-git",
"@openpgp/tweetnacl": "^1.0.4-1", "@openpgp/tweetnacl": "^1.0.4-1",
"@openpgp/web-stream-tools": "^0.0.14", "@openpgp/web-stream-tools": "~0.1.1",
"@rollup/plugin-alias": "^5.0.0", "@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-node-resolve": "^15.0.1", "@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-wasm": "^6.1.2", "@rollup/plugin-wasm": "^6.1.2",

View File

@ -287,7 +287,7 @@ export async function encrypt({ message, encryptionKeys, signingKeys, passwords,
if (!signingKeys) { if (!signingKeys) {
signingKeys = []; signingKeys = [];
} }
const streaming = message.fromStream;
try { try {
if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified
message = await message.sign(signingKeys, signature, signingKeyIDs, date, signingUserIDs, signatureNotations, config); message = await message.sign(signingKeys, signature, signingKeyIDs, date, signingUserIDs, signatureNotations, config);
@ -301,7 +301,7 @@ export async function encrypt({ message, encryptionKeys, signingKeys, passwords,
// serialize data // serialize data
const armor = format === 'armored'; const armor = format === 'armored';
const data = armor ? message.armor(config) : message.write(); const data = armor ? message.armor(config) : message.write();
return convertStream(data, streaming, armor ? 'utf8' : 'binary'); return convertStream(data);
} catch (err) { } catch (err) {
throw util.wrapError('Error encrypting message', err); throw util.wrapError('Error encrypting message', err);
} }
@ -372,7 +372,7 @@ export async function decrypt({ message, decryptionKeys, passwords, sessionKeys,
}) })
]); ]);
} }
result.data = await convertStream(result.data, message.fromStream, format); result.data = await convertStream(result.data);
return result; return result;
} catch (err) { } catch (err) {
throw util.wrapError('Error decrypting message', err); throw util.wrapError('Error decrypting message', err);
@ -438,7 +438,7 @@ export async function sign({ message, signingKeys, format = 'armored', detached
]); ]);
}); });
} }
return convertStream(signature, message.fromStream, armor ? 'utf8' : 'binary'); return convertStream(signature);
} catch (err) { } catch (err) {
throw util.wrapError('Error signing message', err); throw util.wrapError('Error signing message', err);
} }
@ -501,7 +501,7 @@ export async function verify({ message, verificationKeys, expectSigned = false,
}) })
]); ]);
} }
result.data = await convertStream(result.data, message.fromStream, format); result.data = await convertStream(result.data);
return result; return result;
} catch (err) { } catch (err) {
throw util.wrapError('Error verifying signed message', err); throw util.wrapError('Error verifying signed message', err);
@ -672,22 +672,15 @@ function toArray(param) {
/** /**
* Convert data to or from Stream * Convert data to or from Stream
* @param {Object} data - the data to convert * @param {Object} data - the data to convert
* @param {'web'|'node'|false} streaming - Whether to return a ReadableStream, and of what type
* @param {'utf8'|'binary'} [encoding] - How to return data in Node Readable streams
* @returns {Promise<Object>} The data in the respective format. * @returns {Promise<Object>} The data in the respective format.
* @async * @async
* @private * @private
*/ */
async function convertStream(data, streaming, encoding = 'utf8') { async function convertStream(data) {
const streamType = util.isStream(data); const streamType = util.isStream(data);
if (streamType === 'array') { if (streamType === 'array') {
return stream.readToEnd(data); return stream.readToEnd(data);
} }
if (streaming === 'node') {
data = stream.webToNode(data);
if (encoding !== 'binary') data.setEncoding(encoding);
return data;
}
return data; return data;
} }

View File

@ -143,29 +143,10 @@ export default CompressedDataPacket;
// // // //
////////////////////////// //////////////////////////
const nodeZlib = util.getNodeZlib();
function uncompressed(data) { function uncompressed(data) {
return data; return data;
} }
function node_zlib(func, create, options = {}) {
return function (data) {
if (!util.isStream(data) || stream.isArrayStream(data)) {
return stream.fromAsync(() => stream.readToEnd(data).then(data => {
return new Promise((resolve, reject) => {
func(data, options, (err, result) => {
if (err) return reject(err);
resolve(result);
});
});
}));
}
return stream.nodeToWeb(stream.webToNode(data).pipe(create(options)));
};
}
function fflate_zlib(ZlibStreamedConstructor, options) { function fflate_zlib(ZlibStreamedConstructor, options) {
return data => { return data => {
if (!util.isStream(data) || stream.isArrayStream(data)) { if (!util.isStream(data) || stream.isArrayStream(data)) {
@ -216,20 +197,12 @@ function bzip2(func) {
}; };
} }
const compress_fns = nodeZlib ? { const compress_fns = {
zip: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflateRaw, nodeZlib.createDeflateRaw, { level })(compressed),
zlib: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflate, nodeZlib.createDeflate, { level })(compressed)
} : {
zip: /*#__PURE__*/ (compressed, level) => fflate_zlib(Deflate, { level })(compressed), zip: /*#__PURE__*/ (compressed, level) => fflate_zlib(Deflate, { level })(compressed),
zlib: /*#__PURE__*/ (compressed, level) => fflate_zlib(Zlib, { level })(compressed) zlib: /*#__PURE__*/ (compressed, level) => fflate_zlib(Zlib, { level })(compressed)
}; };
const decompress_fns = nodeZlib ? { const decompress_fns = {
uncompressed: uncompressed,
zip: /*#__PURE__*/ node_zlib(nodeZlib.inflateRaw, nodeZlib.createInflateRaw),
zlib: /*#__PURE__*/ node_zlib(nodeZlib.inflate, nodeZlib.createInflate),
bzip2: /*#__PURE__*/ bzip2(BunzipDecode)
} : {
uncompressed: uncompressed, uncompressed: uncompressed,
zip: /*#__PURE__*/ fflate_zlib(Inflate), zip: /*#__PURE__*/ fflate_zlib(Inflate),
zlib: /*#__PURE__*/ fflate_zlib(Unzlib), zlib: /*#__PURE__*/ fflate_zlib(Unzlib),

View File

@ -3840,9 +3840,7 @@ XfA3pqV4mTzF
packets.push(message.packets.findPacket(openpgp.enums.packet.signature)); packets.push(message.packets.findPacket(openpgp.enums.packet.signature));
packets.push(message.packets.findPacket(openpgp.enums.packet.literalData)); packets.push(message.packets.findPacket(openpgp.enums.packet.literalData));
verifyOpt.message = await openpgp.readMessage({ verifyOpt.message = await openpgp.readMessage({
binaryMessage: stream[ binaryMessage: stream.toStream(packets.write())
globalThis.ReadableStream ? 'toStream' : 'webToNode'
](packets.write())
}); });
return openpgp.verify(verifyOpt); return openpgp.verify(verifyOpt);
}).then(async function (verified) { }).then(async function (verified) {

View File

@ -416,7 +416,7 @@ function tests() {
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
const message = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => { armoredMessage: stream.toStream(stream.transform(encrypted, value => {
value += ''; value += '';
const newlineIndex = value.indexOf('\n', 500); const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex); if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@ -453,7 +453,7 @@ function tests() {
expect(stream.isStream(encrypted)).to.equal(expectedType); expect(stream.isStream(encrypted)).to.equal(expectedType);
const message = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(encrypted, value => { armoredMessage: stream.toStream(stream.transform(encrypted, value => {
value += ''; value += '';
const newlineIndex = value.indexOf('\n', 500); const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex); if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@ -486,7 +486,7 @@ function tests() {
expect(stream.isStream(signed)).to.equal(expectedType); expect(stream.isStream(signed)).to.equal(expectedType);
const message = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: stream[expectedType === 'node' ? 'webToNode' : 'toStream'](stream.transform(signed, value => { armoredMessage: stream.toStream(stream.transform(signed, value => {
value += ''; value += '';
const newlineIndex = value.indexOf('\n', 500); const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex); if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
@ -872,6 +872,7 @@ function tests() {
export default () => describe('Streaming', function() { export default () => describe('Streaming', function() {
let currentTest = 0; let currentTest = 0;
const needsStreamPolyfills = !globalThis.ReadableStream;
before(async function() { before(async function() {
pubKey = await openpgp.readKey({ armoredKey: pub_key }); pubKey = await openpgp.readKey({ armoredKey: pub_key });
@ -916,40 +917,41 @@ export default () => describe('Streaming', function() {
tests(); tests();
if (detectNode()) { if (detectNode() && !needsStreamPolyfills) { // ReadableStream polyfills interfere with these tests
const fs = util.nodeRequire('fs'); const fs = util.nodeRequire('fs');
const { Readable: NodeReadableStream } = util.nodeRequire('stream');
const { fileURLToPath } = util.nodeRequire('url'); const { fileURLToPath } = util.nodeRequire('url');
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
it('Node: Encrypt and decrypt text message roundtrip', async function() { it('Node: Encrypt and decrypt text message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived. dataArrived(); // Do not wait until data arrived.
const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js'), 'utf8'); // eslint-disable-line no-sync const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js'), 'utf8'); // eslint-disable-line no-sync
const data = fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js'), { encoding: 'utf8' }); const data = NodeReadableStream.toWeb(fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js'), { encoding: 'utf8' }));
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ text: data }), message: await openpgp.createMessage({ text: data }),
passwords: ['test'] passwords: ['test']
}); });
expect(stream.isStream(encrypted)).to.equal('node'); expect(stream.isStream(encrypted)).to.equal('web');
const message = await openpgp.readMessage({ armoredMessage: encrypted }); const message = await openpgp.readMessage({ armoredMessage: encrypted });
const decrypted = await openpgp.decrypt({ const decrypted = await openpgp.decrypt({
passwords: ['test'], passwords: ['test'],
message message
}); });
expect(stream.isStream(decrypted.data)).to.equal('node'); expect(stream.isStream(decrypted.data)).to.equal('web');
expect(await stream.readToEnd(decrypted.data)).to.equal(plaintext); expect(await stream.readToEnd(decrypted.data)).to.equal(plaintext);
}); });
it('Node: Encrypt and decrypt binary message roundtrip', async function() { it('Node: Encrypt and decrypt binary message roundtrip', async function() {
dataArrived(); // Do not wait until data arrived. dataArrived(); // Do not wait until data arrived.
const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js')); // eslint-disable-line no-sync const plaintext = fs.readFileSync(__filename.replace('streaming.js', 'openpgp.js')); // eslint-disable-line no-sync
const data = fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js')); const data = NodeReadableStream.toWeb(fs.createReadStream(__filename.replace('streaming.js', 'openpgp.js')));
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message: await openpgp.createMessage({ binary: data }), message: await openpgp.createMessage({ binary: data }),
passwords: ['test'], passwords: ['test'],
format: 'binary' format: 'binary'
}); });
expect(stream.isStream(encrypted)).to.equal('node'); expect(stream.isStream(encrypted)).to.equal('web');
const message = await openpgp.readMessage({ binaryMessage: encrypted }); const message = await openpgp.readMessage({ binaryMessage: encrypted });
const decrypted = await openpgp.decrypt({ const decrypted = await openpgp.decrypt({
@ -957,7 +959,7 @@ export default () => describe('Streaming', function() {
message, message,
format: 'binary' format: 'binary'
}); });
expect(stream.isStream(decrypted.data)).to.equal('node'); expect(stream.isStream(decrypted.data)).to.equal('web');
expect(await stream.readToEnd(decrypted.data)).to.deep.equal(plaintext); expect(await stream.readToEnd(decrypted.data)).to.deep.equal(plaintext);
}); });
} }

View File

@ -7,6 +7,7 @@
*/ */
import { ReadableStream as WebReadableStream } from 'web-streams-polyfill'; import { ReadableStream as WebReadableStream } from 'web-streams-polyfill';
import { createReadStream } from 'fs'; import { createReadStream } from 'fs';
import { Readable as NodeNativeReadableStream } from 'stream';
import { expect } from 'chai'; import { expect } from 'chai';
import { import {
@ -15,7 +16,7 @@ import {
encrypt, decrypt, sign, verify, config, enums, encrypt, decrypt, sign, verify, config, enums,
generateSessionKey, encryptSessionKey, decryptSessionKeys, generateSessionKey, encryptSessionKey, decryptSessionKeys,
LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket, CleartextMessage, LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket, CleartextMessage,
WebStream, NodeStream, WebStream, NodeWebStream,
} from 'openpgp'; } from 'openpgp';
(async () => { (async () => {
@ -207,9 +208,9 @@ import {
// Streaming - encrypt text message (armored output) // Streaming - encrypt text message (armored output)
try { try {
const nodeTextStream = createReadStream('non-existent-file', { encoding: 'utf8' }); const nodeTextStream = NodeNativeReadableStream.toWeb(createReadStream('non-existent-file', { encoding: 'utf8' }));
const messageFromNodeTextStream = await createMessage({ text: nodeTextStream }); const messageFromNodeTextStream = await createMessage({ text: nodeTextStream });
(await encrypt({ message: messageFromNodeTextStream, passwords: 'password', format: 'armored' })) as NodeStream<string>; (await encrypt({ message: messageFromNodeTextStream, passwords: 'password', format: 'armored' })) as NodeWebStream<string>;
} catch (err) {} } catch (err) {}
const webTextStream = new WebReadableStream<string>(); const webTextStream = new WebReadableStream<string>();
const messageFromWebTextStream = await createMessage({ text: webTextStream }); const messageFromWebTextStream = await createMessage({ text: webTextStream });
@ -219,9 +220,9 @@ import {
// Streaming - encrypt binary message (binary output) // Streaming - encrypt binary message (binary output)
try { try {
const nodeBinaryStream = createReadStream('non-existent-file'); const nodeBinaryStream = NodeNativeReadableStream.toWeb(createReadStream('non-existent-file'));
const messageFromNodeBinaryStream = await createMessage({ binary: nodeBinaryStream }); const messageFromNodeBinaryStream = await createMessage({ binary: nodeBinaryStream });
(await encrypt({ message: messageFromNodeBinaryStream, passwords: 'password', format: 'binary' })) as NodeStream<Uint8Array>; (await encrypt({ message: messageFromNodeBinaryStream, passwords: 'password', format: 'binary' })) as NodeWebStream<Uint8Array>;
} catch (err) {} } catch (err) {}
const webBinaryStream = new WebReadableStream<Uint8Array>(); const webBinaryStream = new WebReadableStream<Uint8Array>();
const messageFromWebBinaryStream = await createMessage({ binary: webBinaryStream }); const messageFromWebBinaryStream = await createMessage({ binary: webBinaryStream });

View File

@ -27,7 +27,10 @@ globalThis.tryTests = function(name, tests, options) {
}; };
globalThis.loadStreamsPolyfill = function() { globalThis.loadStreamsPolyfill = function() {
return import('web-streams-polyfill'); // do not polyfill Node
const detectNodeWebStreams = () => typeof globalThis.process === 'object' && typeof globalThis.process.versions === 'object' && globalThis.ReadableStream;
return detectNodeWebStreams() || import('web-streams-polyfill');
}; };
import runWorkerTests from './worker'; import runWorkerTests from './worker';