@zip.js/zip.js 2.16.0 → 2.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +284 -179
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +108 -61
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +426 -189
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +251 -70
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +426 -189
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +253 -72
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +428 -189
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +110 -63
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +110 -63
  19. package/dist/zip-native.min.js +1 -1
  20. package/dist/zip-web-worker-native.js +1 -1
  21. package/dist/zip-web-worker.js +1 -1
  22. package/dist/zip.js +285 -180
  23. package/dist/zip.min.js +1 -1
  24. package/eslint.config.mjs +1 -1
  25. package/index-native.cjs +253 -72
  26. package/index-native.min.js +1 -1
  27. package/index.cjs +428 -189
  28. package/index.d.cts +117 -16
  29. package/index.d.ts +117 -16
  30. package/index.min.js +1 -1
  31. package/lib/core/streams/aes-crypto-stream.js +60 -17
  32. package/lib/core/streams/zip-crypto-stream.js +7 -7
  33. package/lib/core/streams/zip-entry-stream.js +22 -26
  34. package/lib/core/streams/zlib-wasm/zlib-streams.js +176 -118
  35. package/lib/core/util/compatible-streams.js +10 -5
  36. package/lib/core/version.js +1 -1
  37. package/lib/core/web-worker-inline-native.js +1 -1
  38. package/lib/core/web-worker-inline-wasm.js +1 -1
  39. package/lib/core/zip-fs.js +144 -10
  40. package/lib/core/zip-reader.js +5 -5
  41. package/lib/core/zip-writer.js +4 -2
  42. package/package.json +3 -2
package/dist/zip-core.js CHANGED
@@ -1283,12 +1283,12 @@
1283
1283
  class AESDecryptionStream extends TransformStream {
1284
1284
 
1285
1285
  constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly, checkAuthenticationCode = true }) {
1286
+ const aesCrypto = {};
1286
1287
  super({
1287
1288
  start() {
1288
- initAesCrypto(this, password, rawPassword, encryptionStrength);
1289
+ initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength);
1289
1290
  },
1290
1291
  async transform(chunk, controller) {
1291
- const aesCrypto = this;
1292
1292
  const {
1293
1293
  password,
1294
1294
  strength,
@@ -1307,6 +1307,9 @@
1307
1307
  } else {
1308
1308
  await ready;
1309
1309
  }
1310
+ if (aesCrypto.discarded) {
1311
+ return;
1312
+ }
1310
1313
  const output = new Uint8Array(chunk.length - AUTHENTICATION_CODE_LENGTH - ((chunk.length - AUTHENTICATION_CODE_LENGTH) % BLOCK_LENGTH));
1311
1314
  controller.enqueue(append(aesCrypto, chunk, output, 0, AUTHENTICATION_CODE_LENGTH, true));
1312
1315
  },
@@ -1315,9 +1318,12 @@
1315
1318
  engine,
1316
1319
  pendingInput,
1317
1320
  ready
1318
- } = this;
1321
+ } = aesCrypto;
1319
1322
  if (engine) {
1320
1323
  await ready;
1324
+ if (aesCrypto.discarded) {
1325
+ return;
1326
+ }
1321
1327
  const originalAuthenticationCode = subarray(pendingInput, pendingInput.length - AUTHENTICATION_CODE_LENGTH);
1322
1328
  const decryptedChunkArray = new Uint8Array(subarray(pendingInput, 0, pendingInput.length - AUTHENTICATION_CODE_LENGTH));
1323
1329
  engine.process(decryptedChunkArray, true);
@@ -1327,27 +1333,26 @@
1327
1333
  invalidAuthenticationCode |= authenticationCode[indexByte] ^ originalAuthenticationCode[indexByte];
1328
1334
  }
1329
1335
  if (invalidAuthenticationCode && checkAuthenticationCode) {
1330
- throw new Error(ERR_INVALID_AUTHENTICATION_CODE);
1336
+ controller.error(new Error(ERR_INVALID_AUTHENTICATION_CODE));
1337
+ return;
1331
1338
  }
1332
1339
  controller.enqueue(decryptedChunkArray);
1333
1340
  }
1334
- },
1335
- cancel() {
1336
- disposeEngine(this);
1337
1341
  }
1338
1342
  });
1343
+ setDisposingReadable(this, aesCrypto);
1339
1344
  }
1340
1345
  }
1341
1346
 
1342
1347
  class AESEncryptionStream extends TransformStream {
1343
1348
 
1344
1349
  constructor({ password, rawPassword, encryptionStrength }) {
1350
+ const aesCrypto = {};
1345
1351
  super({
1346
1352
  start() {
1347
- initAesCrypto(this, password, rawPassword, encryptionStrength);
1353
+ initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength);
1348
1354
  },
1349
1355
  async transform(chunk, controller) {
1350
- const aesCrypto = this;
1351
1356
  const {
1352
1357
  password,
1353
1358
  strength,
@@ -1361,6 +1366,9 @@
1361
1366
  } else {
1362
1367
  await ready;
1363
1368
  }
1369
+ if (aesCrypto.discarded) {
1370
+ return;
1371
+ }
1364
1372
  const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
1365
1373
  output.set(preamble, 0);
1366
1374
  controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0, false));
@@ -1370,19 +1378,20 @@
1370
1378
  engine,
1371
1379
  pendingInput,
1372
1380
  ready
1373
- } = this;
1381
+ } = aesCrypto;
1374
1382
  if (engine) {
1375
1383
  await ready;
1384
+ if (aesCrypto.discarded) {
1385
+ return;
1386
+ }
1376
1387
  const encryptedChunkArray = new Uint8Array(pendingInput);
1377
1388
  engine.process(encryptedChunkArray, false);
1378
1389
  const authenticationCode = subarray(engine.digest(), 0, AUTHENTICATION_CODE_LENGTH);
1379
1390
  controller.enqueue(concat(encryptedChunkArray, authenticationCode));
1380
1391
  }
1381
- },
1382
- cancel() {
1383
- disposeEngine(this);
1384
1392
  }
1385
1393
  });
1394
+ setDisposingReadable(this, aesCrypto);
1386
1395
  }
1387
1396
  }
1388
1397
 
@@ -1391,7 +1400,37 @@
1391
1400
  ready: new Promise(resolve => aesCrypto.resolveReady = resolve),
1392
1401
  password: encodePassword(password, rawPassword),
1393
1402
  strength: encryptionStrength - 1,
1394
- pendingInput: EMPTY_UINT8_ARRAY
1403
+ pendingInput: EMPTY_UINT8_ARRAY,
1404
+ discarded: false
1405
+ });
1406
+ }
1407
+
1408
+ function setDisposingReadable(stream, aesCrypto) {
1409
+ const reader = stream.readable.getReader();
1410
+ const readable = new ReadableStream({
1411
+ async pull(controller) {
1412
+ try {
1413
+ const { value, done } = await reader.read();
1414
+ if (done) {
1415
+ controller.close();
1416
+ } else {
1417
+ controller.enqueue(value);
1418
+ }
1419
+ } catch (error) {
1420
+ disposeEngine(aesCrypto);
1421
+ reader.cancel(error).catch(() => { });
1422
+ throw error;
1423
+ }
1424
+ },
1425
+ cancel(reason) {
1426
+ disposeEngine(aesCrypto);
1427
+ return reader.cancel(reason);
1428
+ }
1429
+ });
1430
+ Object.defineProperty(stream, "readable", {
1431
+ get() {
1432
+ return readable;
1433
+ }
1395
1434
  });
1396
1435
  }
1397
1436
 
@@ -1424,7 +1463,9 @@
1424
1463
  }
1425
1464
  }
1426
1465
 
1427
- function disposeEngine({ engine }) {
1466
+ function disposeEngine(aesCrypto) {
1467
+ const { engine } = aesCrypto;
1468
+ aesCrypto.discarded = true;
1428
1469
  if (engine && engine.dispose) {
1429
1470
  engine.dispose();
1430
1471
  }
@@ -1441,6 +1482,9 @@
1441
1482
  const keyLength = KEY_LENGTH[strength];
1442
1483
  const compositeKey = await deriveKey(password, salt, keyLength * 2 + PASSWORD_VERIFICATION_LENGTH);
1443
1484
  aesCrypto.engine = createEngine(subarray(compositeKey, 0, keyLength), subarray(compositeKey, keyLength, keyLength * 2));
1485
+ if (aesCrypto.discarded) {
1486
+ disposeEngine(aesCrypto);
1487
+ }
1444
1488
  return subarray(compositeKey, keyLength * 2);
1445
1489
  }
1446
1490
 
@@ -1592,11 +1636,11 @@
1592
1636
  }
1593
1637
 
1594
1638
  function createKeys(target, password, rawPassword) {
1595
- const keys = [0x12345678, 0x23456789, 0x34567890];
1639
+ const cryptoKeys = [0x12345678, 0x23456789, 0x34567890];
1596
1640
  Object.assign(target, {
1597
- keys,
1598
- crcKey0: new Crc32(keys[0]),
1599
- crcKey2: new Crc32(keys[2])
1641
+ cryptoKeys,
1642
+ crcKey0: new Crc32(cryptoKeys[0]),
1643
+ crcKey2: new Crc32(cryptoKeys[2])
1600
1644
  });
1601
1645
  if (rawPassword) {
1602
1646
  for (let index = 0; index < rawPassword.length; index++) {
@@ -1610,17 +1654,17 @@
1610
1654
  }
1611
1655
 
1612
1656
  function updateKeys(target, byte) {
1613
- let [, key1] = target.keys;
1657
+ let [, key1] = target.cryptoKeys;
1614
1658
  target.crcKey0.append([byte]);
1615
1659
  const key0 = ~target.crcKey0.get();
1616
1660
  key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
1617
1661
  target.crcKey2.append([key1 >>> 24]);
1618
1662
  const key2 = ~target.crcKey2.get();
1619
- target.keys = [key0, key1, key2];
1663
+ target.cryptoKeys = [key0, key1, key2];
1620
1664
  }
1621
1665
 
1622
1666
  function getByte(target) {
1623
- const temp = target.keys[2] | 2;
1667
+ const temp = target.cryptoKeys[2] | 2;
1624
1668
  return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8);
1625
1669
  }
1626
1670
 
@@ -1668,11 +1712,16 @@
1668
1712
  const reader = readable.getReader();
1669
1713
  return new ReadableStream({
1670
1714
  async pull(controller) {
1671
- const { value, done } = await reader.read();
1672
- if (done) {
1673
- controller.close();
1674
- } else {
1675
- controller.enqueue(value);
1715
+ try {
1716
+ const { value, done } = await reader.read();
1717
+ if (done) {
1718
+ controller.close();
1719
+ } else {
1720
+ controller.enqueue(value);
1721
+ }
1722
+ } catch (error) {
1723
+ reader.cancel(error).catch(() => { });
1724
+ throw error;
1676
1725
  }
1677
1726
  },
1678
1727
  cancel(reason) {
@@ -1975,28 +2024,25 @@
1975
2024
  pump();
1976
2025
  return new ReadableStream({
1977
2026
  async pull(controller) {
1978
- let result;
1979
2027
  try {
1980
- result = await read();
2028
+ const { value, done } = await read();
2029
+ if (done) {
2030
+ controller.close();
2031
+ } else {
2032
+ outputLength += value.length;
2033
+ if (outputLength > outputSize) {
2034
+ throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
2035
+ }
2036
+ if (outputCrc32) {
2037
+ outputCrc32.append(value);
2038
+ }
2039
+ controller.enqueue(value);
2040
+ }
1981
2041
  } catch (error) {
2042
+ rejectTrailerReady(error);
2043
+ await cancel(reader, error);
1982
2044
  throw trailerWritten ? getTrailerError(error) : error;
1983
2045
  }
1984
- const { value, done } = result;
1985
- if (done) {
1986
- controller.close();
1987
- } else {
1988
- outputLength += value.length;
1989
- if (outputLength > outputSize) {
1990
- const error = new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
1991
- rejectTrailerReady(error);
1992
- await cancel(reader, error);
1993
- throw error;
1994
- }
1995
- if (outputCrc32) {
1996
- outputCrc32.append(value);
1997
- }
1998
- controller.enqueue(value);
1999
- }
2000
2046
  },
2001
2047
  cancel(reason) {
2002
2048
  rejectTrailerReady(reason);
@@ -2275,10 +2321,15 @@
2275
2321
  const reader = readable.getReader();
2276
2322
  return new ReadableStream({
2277
2323
  async pull(controller) {
2278
- let result;
2279
2324
  try {
2280
- result = await reader.read();
2325
+ const { value, done } = await reader.read();
2326
+ if (done) {
2327
+ controller.close();
2328
+ } else {
2329
+ controller.enqueue(value);
2330
+ }
2281
2331
  } catch (error) {
2332
+ await cancel(reader, error);
2282
2333
  if (error && error.message) {
2283
2334
  throw error;
2284
2335
  }
@@ -2286,12 +2337,6 @@
2286
2337
  mappedError.cause = error;
2287
2338
  throw mappedError;
2288
2339
  }
2289
- const { value, done } = result;
2290
- if (done) {
2291
- controller.close();
2292
- } else {
2293
- controller.enqueue(value);
2294
- }
2295
2340
  },
2296
2341
  cancel(reason) {
2297
2342
  return reader.cancel(reason);
@@ -5346,8 +5391,8 @@
5346
5391
  const passThroughCompression = Boolean(passThrough);
5347
5392
  const passThroughEncryption = passThrough === true;
5348
5393
  checkPasswordOption(password, rawPassword);
5349
- password = password && password.length && password;
5350
- rawPassword = rawPassword && rawPassword.length && rawPassword;
5394
+ password = password && password.length ? password : UNDEFINED_VALUE;
5395
+ rawPassword = rawPassword && rawPassword.length ? rawPassword : UNDEFINED_VALUE;
5351
5396
  if (extraFieldAES) {
5352
5397
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
5353
5398
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
@@ -6108,7 +6153,7 @@
6108
6153
  async function findEndOfCentralDirectory(reader, rejectAmbiguous, maxAppendedDataSize) {
6109
6154
  const { size } = reader;
6110
6155
  const anchoredLength = Math.min(size, END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS);
6111
- const remoteProbeBudget = { count: MAX_END_OF_CENTRAL_DIR_PROBES };
6156
+ const remoteProbeBudget = { remaining: MAX_END_OF_CENTRAL_DIR_PROBES };
6112
6157
  let endOfDirectoryInfo;
6113
6158
  let plausibleEndOfDirectoryInfo;
6114
6159
  let endOfDirectoryReachingEndCount = 0;
@@ -6201,8 +6246,8 @@
6201
6246
  if (signatureOffset >= anchoredOffset) {
6202
6247
  return getUint32$1(view, signatureOffset - anchoredOffset);
6203
6248
  }
6204
- if (remoteProbeBudget.count > 0) {
6205
- remoteProbeBudget.count--;
6249
+ if (remoteProbeBudget.remaining > 0) {
6250
+ remoteProbeBudget.remaining--;
6206
6251
  const signatureArray = await readUint8Array(reader, signatureOffset, 4);
6207
6252
  return getUint32$1(getDataView(signatureArray), 0);
6208
6253
  }
@@ -7118,9 +7163,11 @@
7118
7163
  const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
7119
7164
  const passThroughCompression = Boolean(passThrough);
7120
7165
  const passThroughEncryption = passThrough === true;
7121
- const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
7122
- const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
7166
+ let password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
7167
+ let rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
7123
7168
  checkPasswordOption(password, rawPassword);
7169
+ password = password && password.length ? password : UNDEFINED_VALUE;
7170
+ rawPassword = rawPassword && rawPassword.length ? rawPassword : UNDEFINED_VALUE;
7124
7171
  const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
7125
7172
  const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
7126
7173
  const extendedTimestamp = getOptionValue(zipWriter, options, OPTION_EXTENDED_TIMESTAMP, true);
@@ -8818,7 +8865,7 @@
8818
8865
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8819
8866
  */
8820
8867
 
8821
- const VERSION = "2.16.0";
8868
+ const VERSION = "2.16.1";
8822
8869
 
8823
8870
  /*
8824
8871
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.