Use Compression Stream API when available, drop config.deflateLevel (#1717)

Breaking change: the `config.deflateLevel` is removed as the API does not accept a deflate level
in input, and the setting is of limited importance. Plus, using compression
is discouraged on security grounds.
This commit is contained in:
larabr 2024-02-01 09:42:16 +01:00 committed by GitHub
parent 99899d1d5c
commit 959956cfc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 42 additions and 26 deletions

1
openpgp.d.ts vendored
View File

@ -323,7 +323,6 @@ interface Config {
preferredCompressionAlgorithm: enums.compression; preferredCompressionAlgorithm: enums.compression;
showVersion: boolean; showVersion: boolean;
showComment: boolean; showComment: boolean;
deflateLevel: number;
aeadProtect: boolean; aeadProtect: boolean;
allowUnauthenticatedMessages: boolean; allowUnauthenticatedMessages: boolean;
allowUnauthenticatedStream: boolean; allowUnauthenticatedStream: boolean;

View File

@ -37,11 +37,6 @@ export default {
* @property {Integer} compression Default compression algorithm {@link module:enums.compression} * @property {Integer} compression Default compression algorithm {@link module:enums.compression}
*/ */
preferredCompressionAlgorithm: enums.compression.uncompressed, preferredCompressionAlgorithm: enums.compression.uncompressed,
/**
* @memberof module:config
* @property {Integer} deflateLevel Default zip/zlib compression level, between 1 and 9
*/
deflateLevel: 6,
/** /**
* Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption. * Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption.
* This option is applicable to: * This option is applicable to:

View File

@ -67,11 +67,6 @@ class CompressedDataPacket {
* @type {Uint8Array | ReadableStream<Uint8Array>} * @type {Uint8Array | ReadableStream<Uint8Array>}
*/ */
this.compressed = null; this.compressed = null;
/**
* zip/zlib compression level, between 1 and 9
*/
this.deflateLevel = config.deflateLevel;
} }
/** /**
@ -131,7 +126,7 @@ class CompressedDataPacket {
throw new Error(`${compressionName} compression not supported`); throw new Error(`${compressionName} compression not supported`);
} }
this.compressed = compressionFn(this.packets.write(), this.deflateLevel); this.compressed = compressionFn(this.packets.write());
} }
} }
@ -143,16 +138,18 @@ export default CompressedDataPacket;
// // // //
////////////////////////// //////////////////////////
function uncompressed(data) { /**
return data; * Zlib processor relying on Compression Stream API if available, or falling back to fflate otherwise.
} * @param {function(): CompressionStream|function(): DecompressionStream} compressionStreamInstantiator
* @param {FunctionConstructor} ZlibStreamedConstructor - fflate constructor
function fflate_zlib(ZlibStreamedConstructor, options) { * @returns {ReadableStream<Uint8Array>} compressed or decompressed data
*/
function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) {
return data => { return data => {
if (!util.isStream(data) || stream.isArrayStream(data)) { if (!util.isStream(data) || stream.isArrayStream(data)) {
return stream.fromAsync(() => stream.readToEnd(data).then(inputData => { return stream.fromAsync(() => stream.readToEnd(data).then(inputData => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const zlibStream = new ZlibStreamedConstructor(options); const zlibStream = new ZlibStreamedConstructor();
zlibStream.ondata = processedData => { zlibStream.ondata = processedData => {
resolve(processedData); resolve(processedData);
}; };
@ -165,8 +162,22 @@ function fflate_zlib(ZlibStreamedConstructor, options) {
})); }));
} }
// Use Compression Streams API if available (see https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API)
if (compressionStreamInstantiator) {
try {
const compressorOrDecompressor = compressionStreamInstantiator();
return data.pipeThrough(compressorOrDecompressor);
} catch (err) {
// If format is unsupported in Compression/DecompressionStream, then a TypeError in thrown, and we fallback to fflate.
if (err.name !== 'TypeError') {
throw err;
}
}
}
// JS fallback
const inputReader = data.getReader(); const inputReader = data.getReader();
const zlibStream = new ZlibStreamedConstructor(options); const zlibStream = new ZlibStreamedConstructor();
return new ReadableStream({ return new ReadableStream({
async start(controller) { async start(controller) {
@ -197,15 +208,27 @@ function bzip2(func) {
}; };
} }
/**
* Get Compression Stream API instatiators if the constructors are implemented.
* NB: the return instatiator functions will throw when called if the provided `compressionFormat` is not supported
* (supported formats cannot be determined in advance).
* @param {'deflate-raw'|'deflate'|'gzip'|string} compressionFormat
* @returns {{ compressor: function(): CompressionStream | false, decompressor: function(): DecompressionStream | false }}
*/
const getCompressionStreamInstantiators = compressionFormat => ({
compressor: typeof CompressionStream !== 'undefined' && (() => new CompressionStream(compressionFormat)),
decompressor: typeof DecompressionStream !== 'undefined' && (() => new DecompressionStream(compressionFormat))
});
const compress_fns = { const compress_fns = {
zip: /*#__PURE__*/ (compressed, level) => fflate_zlib(Deflate, { level })(compressed), zip: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate-raw').compressor, Deflate),
zlib: /*#__PURE__*/ (compressed, level) => fflate_zlib(Zlib, { level })(compressed) zlib: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate').compressor, Zlib)
}; };
const decompress_fns = { const decompress_fns = {
uncompressed: uncompressed, uncompressed: data => data,
zip: /*#__PURE__*/ fflate_zlib(Inflate), zip: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate-raw').decompressor, Inflate),
zlib: /*#__PURE__*/ fflate_zlib(Unzlib), zlib: /*#__PURE__*/ zlib(getCompressionStreamInstantiators('deflate').decompressor, Unzlib),
bzip2: /*#__PURE__*/ bzip2(BunzipDecode) bzip2: /*#__PURE__*/ bzip2(BunzipDecode)
}; };

View File

@ -278,8 +278,7 @@ n9/quqtmyOtYOA6gXNCw0Fal3iANKBmsPmYI
const config = { const config = {
aeadProtect: true, aeadProtect: true,
preferredCompressionAlgorithm: openpgp.enums.compression.zip, preferredCompressionAlgorithm: openpgp.enums.compression.zip
deflateLevel: 1
}; };
const armored2 = await openpgp.encrypt({ message, passwords, config }); const armored2 = await openpgp.encrypt({ message, passwords, config });
const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 }); const encrypted2 = await openpgp.readMessage({ armoredMessage: armored2 });