@zip.js/zip.js 2.8.46 → 2.8.48

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 (50) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +130 -35
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +140 -34
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +131 -36
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +115 -32
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +131 -36
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +145 -37
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +144 -36
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +142 -36
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +142 -36
  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 +141 -35
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +145 -37
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +144 -36
  27. package/index.d.cts +141 -0
  28. package/index.d.ts +141 -0
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-pool.js +6 -3
  31. package/lib/core/codec-worker.js +2 -1
  32. package/lib/core/constants.js +2 -0
  33. package/lib/core/io.js +3 -23
  34. package/lib/core/options.js +4 -0
  35. package/lib/core/streams/codec-stream.js +2 -0
  36. package/lib/core/streams/common-crypto.js +2 -1
  37. package/lib/core/streams/zip-entry-stream.js +4 -2
  38. package/lib/core/util/blob-temp-stream.js +4 -2
  39. package/lib/core/util/compatible-streams.js +30 -2
  40. package/lib/core/util/opfs-temp-stream.js +8 -1
  41. package/lib/core/util/sync-access-handle-temp-stream.js +10 -2
  42. package/lib/core/web-worker-inline-native.js +1 -1
  43. package/lib/core/web-worker-inline-wasm.js +1 -1
  44. package/lib/core/zip-fs.js +3 -2
  45. package/lib/core/zip-reader.js +62 -9
  46. package/lib/core/zip-writer.js +43 -8
  47. package/lib/zip-core-base.js +2 -1
  48. package/lib/zip-core-reader.js +2 -1
  49. package/lib/zip-core-writer.js +10 -1
  50. package/package.json +2 -1
@@ -46,6 +46,7 @@
46
46
  const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
47
47
  const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
48
48
  const ARCHIVE_EXTRA_DATA_SIGNATURE = 0x08064b50;
49
+ const DIGITAL_SIGNATURE_RECORD_SIGNATURE = 0x05054b50;
49
50
  const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
50
51
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
51
52
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
@@ -254,6 +255,8 @@
254
255
  */
255
256
 
256
257
 
258
+ const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
259
+
257
260
  function toCompatibleReadable(readable) {
258
261
  if (readable instanceof ReadableStream) {
259
262
  return readable;
@@ -274,6 +277,29 @@
274
277
  });
275
278
  }
276
279
 
280
+ function streamToBlob(readable, contentType) {
281
+ readable = toCompatibleReadable(readable);
282
+ if (responseSupportsGlobalReadable()) {
283
+ const options = {};
284
+ if (contentType) {
285
+ options.headers = [[HTTP_HEADER_CONTENT_TYPE, contentType]];
286
+ }
287
+ return new Response(readable, options).blob();
288
+ }
289
+ const chunks = [];
290
+ return readable
291
+ .pipeTo(new WritableStream({
292
+ write(chunk) {
293
+ chunks.push(chunk);
294
+ }
295
+ }))
296
+ .then(() => new Blob(chunks, contentType ? { type: contentType } : {}));
297
+ }
298
+
299
+ function responseSupportsGlobalReadable() {
300
+ return typeof Blob.prototype.stream != FUNCTION_TYPE || new Blob([]).stream() instanceof ReadableStream;
301
+ }
302
+
277
303
  function toCompatibleWritable(writable) {
278
304
  if (writable instanceof WritableStream) {
279
305
  return writable;
@@ -333,7 +359,6 @@
333
359
  const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
334
360
  const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
335
361
  const HTTP_HEADER_RANGE = "Range";
336
- const HTTP_HEADER_CONTENT_TYPE = "Content-Type";
337
362
  const HTTP_HEADER_ETAG = "Etag";
338
363
  const HTTP_HEADER_LAST_MODIFIED = "Last-Modified";
339
364
  const HTTP_METHOD_HEAD = "HEAD";
@@ -538,10 +563,6 @@
538
563
  }
539
564
  }
540
565
 
541
- function responseSupportsGlobalReadable() {
542
- return typeof Blob.prototype.stream != FUNCTION_TYPE || new Blob([]).stream() instanceof ReadableStream;
543
- }
544
-
545
566
  class BlobWriter extends Stream {
546
567
 
547
568
  constructor(contentType) {
@@ -553,22 +574,7 @@
553
574
  return transformStream.writable;
554
575
  }
555
576
  });
556
- if (responseSupportsGlobalReadable()) {
557
- const headers = [];
558
- if (contentType) {
559
- headers.push([HTTP_HEADER_CONTENT_TYPE, contentType]);
560
- }
561
- writer.blob = new Response(transformStream.readable, { headers }).blob();
562
- } else {
563
- const chunks = [];
564
- writer.blob = transformStream.readable
565
- .pipeTo(new WritableStream({
566
- write(chunk) {
567
- chunks.push(chunk);
568
- }
569
- }))
570
- .then(() => new Blob(chunks, { type: contentType }));
571
- }
577
+ writer.blob = streamToBlob(transformStream.readable, contentType);
572
578
  writer.blob.catch(() => { });
573
579
  }
574
580
 
@@ -4329,6 +4335,8 @@
4329
4335
  const OPTION_LOCAL_EXTRA_FIELD = "localExtraField";
4330
4336
  const OPTION_STRICTNESS = "strictness";
4331
4337
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
4338
+ const OPTION_DECRYPT_CENTRAL_DIRECTORY = "decryptCentralDirectory";
4339
+ const OPTION_SIGN_CENTRAL_DIRECTORY = "signCentralDirectory";
4332
4340
  const STRICTNESS_STRICT = "strict";
4333
4341
  const STRICTNESS_BALANCED = "balanced";
4334
4342
  const STRICTNESS_TOLERANT = "tolerant";
@@ -4414,7 +4422,7 @@
4414
4422
  const { config } = zipReader;
4415
4423
  await initStream(reader);
4416
4424
  if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
4417
- reader = new BlobReader(await new Response(reader.readable).blob());
4425
+ reader = new BlobReader(await streamToBlob(reader.readable));
4418
4426
  await initStream(reader);
4419
4427
  }
4420
4428
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
@@ -4454,6 +4462,7 @@
4454
4462
  let startOffset;
4455
4463
  let zip64EndOfDirectory;
4456
4464
  let zip64EndOfDirectoryVersion2;
4465
+ let directoryEncryptionInfo;
4457
4466
  const requiresZip64 = directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS;
4458
4467
  if (directoryDataOffset != MAX_32_BITS && diskNumber != MAX_16_BITS) {
4459
4468
  directoryDataOffset += getDiskOffset$1(reader, diskNumber);
@@ -4484,6 +4493,15 @@
4484
4493
  }
4485
4494
  zip64EndOfDirectory = true;
4486
4495
  zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
4496
+ if (zip64EndOfDirectoryVersion2) {
4497
+ const extensibleDataLength = Math.min(
4498
+ Number(getBigUint64(endOfDirectoryView, 4)) - (ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12),
4499
+ reader.size - directoryDataOffset - ZIP64_END_OF_CENTRAL_DIR_LENGTH);
4500
+ if (extensibleDataLength > 0) {
4501
+ const rawExtensibleData = await readUint8Array(reader, directoryDataOffset + ZIP64_END_OF_CENTRAL_DIR_LENGTH, extensibleDataLength);
4502
+ directoryEncryptionInfo = getDirectoryEncryptionInfo(rawExtensibleData);
4503
+ }
4504
+ }
4487
4505
  if (lastDiskNumber == MAX_16_BITS) {
4488
4506
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
4489
4507
  } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
@@ -4507,7 +4525,7 @@
4507
4525
  directoryDataOffset = getDiskOffset$1(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
4508
4526
  }
4509
4527
  }
4510
- const declaredDirectoryDataLength = directoryDataLength;
4528
+ let declaredDirectoryDataLength = directoryDataLength;
4511
4529
  const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
4512
4530
  (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
4513
4531
  if (directoryDataOffset >= reader.size) {
@@ -4555,6 +4573,18 @@
4555
4573
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
4556
4574
  throw new Error(ERR_BAD_FORMAT);
4557
4575
  }
4576
+ zipReader.directoryOffset = directoryDataOffset;
4577
+ zipReader.directoryLength = declaredDirectoryDataLength;
4578
+ const decryptCentralDirectory = getOptionValue$1(zipReader, options, OPTION_DECRYPT_CENTRAL_DIRECTORY);
4579
+ let decryptedDirectory;
4580
+ if (decryptCentralDirectory && filesLength && directoryArray.length >= 4 &&
4581
+ getUint32(directoryView, 0) != CENTRAL_FILE_HEADER_SIGNATURE &&
4582
+ (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
4583
+ directoryArray = await decryptCentralDirectory(directoryArray, directoryEncryptionInfo);
4584
+ directoryView = getDataView(directoryArray);
4585
+ declaredDirectoryDataLength = directoryArray.length;
4586
+ decryptedDirectory = true;
4587
+ }
4558
4588
  startOffset = directoryDataOffset;
4559
4589
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
4560
4590
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
@@ -4563,7 +4593,7 @@
4563
4593
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4564
4594
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
4565
4595
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
4566
- if (indexFile == 0 && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
4596
+ if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
4567
4597
  throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
4568
4598
  }
4569
4599
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
@@ -4661,7 +4691,7 @@
4661
4691
  entry.arrayBuffer = async options => {
4662
4692
  const writer = new TransformStream();
4663
4693
  const [arrayBuffer] = await Promise.all([
4664
- new Response(writer.readable).arrayBuffer(),
4694
+ streamToBlob(writer.readable).then(blob => blob.arrayBuffer()),
4665
4695
  fileEntry.getData(writer, entry, zipReader.readRanges, options)]);
4666
4696
  return arrayBuffer;
4667
4697
  };
@@ -4676,7 +4706,15 @@
4676
4706
  }
4677
4707
  yield entry;
4678
4708
  }
4679
- if (checkAmbiguity && offset != declaredDirectoryDataLength) {
4709
+ let offsetAfterSignature = offset;
4710
+ if (offset + 6 <= directoryArray.length && getUint32(directoryView, offset) == DIGITAL_SIGNATURE_RECORD_SIGNATURE) {
4711
+ const signatureDataLength = getUint16(directoryView, offset + 4);
4712
+ if (offset + 6 + signatureDataLength <= directoryArray.length) {
4713
+ zipReader.digitalSignature = directoryArray.subarray(offset + 6, offset + 6 + signatureDataLength);
4714
+ offsetAfterSignature = offset + 6 + signatureDataLength;
4715
+ }
4716
+ }
4717
+ if (checkAmbiguity && offset != declaredDirectoryDataLength && offsetAfterSignature != declaredDirectoryDataLength) {
4680
4718
  throwAmbiguousArchive("trailing central directory data");
4681
4719
  }
4682
4720
  if (duplicateFilename) {
@@ -4908,6 +4946,25 @@
4908
4946
  return false;
4909
4947
  }
4910
4948
 
4949
+ function getDirectoryEncryptionInfo(rawExtensibleData) {
4950
+ const directoryEncryptionInfo = { rawExtensibleData };
4951
+ if (rawExtensibleData.length >= 28) {
4952
+ const extensibleDataView = getDataView(rawExtensibleData);
4953
+ const hashDataLength = getUint16(extensibleDataView, 26);
4954
+ Object.assign(directoryEncryptionInfo, {
4955
+ compressionMethod: getUint16(extensibleDataView, 0),
4956
+ compressedSize: Number(getBigUint64(extensibleDataView, 2)),
4957
+ uncompressedSize: Number(getBigUint64(extensibleDataView, 10)),
4958
+ encryptionAlgorithm: getUint16(extensibleDataView, 18),
4959
+ bitLength: getUint16(extensibleDataView, 20),
4960
+ flags: getUint16(extensibleDataView, 22),
4961
+ hashAlgorithm: getUint16(extensibleDataView, 24),
4962
+ hashData: rawExtensibleData.subarray(28, 28 + hashDataLength)
4963
+ });
4964
+ }
4965
+ return directoryEncryptionInfo;
4966
+ }
4967
+
4911
4968
  function readCommonHeader(directory, dataView, offset) {
4912
4969
  const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2);
4913
4970
  const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED;
@@ -5459,6 +5516,7 @@
5459
5516
  ERR_SPLIT_ZIP_FILE: ERR_SPLIT_ZIP_FILE,
5460
5517
  ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION$1,
5461
5518
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
5519
+ ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
5462
5520
  ZipReader: ZipReader
5463
5521
  });
5464
5522
 
@@ -5516,6 +5574,7 @@
5516
5574
  const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
5517
5575
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
5518
5576
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
5577
+ const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
5519
5578
 
5520
5579
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
5521
5580
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
@@ -6813,8 +6872,9 @@
6813
6872
 
6814
6873
  async function closeFile(zipWriter, comment, options) {
6815
6874
  const directoryDataLength = createDirectoryRecords(zipWriter.files);
6816
- const directoryStart = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6817
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength });
6875
+ const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6876
+ const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
6877
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
6818
6878
  }
6819
6879
 
6820
6880
  function createDirectoryRecords(files) {
@@ -6971,12 +7031,33 @@
6971
7031
  }
6972
7032
  }
6973
7033
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
6974
- return { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset };
7034
+ return {
7035
+ directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
7036
+ directoryArray
7037
+ };
7038
+ }
7039
+
7040
+ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
7041
+ const signCentralDirectory = getOptionValue(zipWriter, options, OPTION_SIGN_CENTRAL_DIRECTORY);
7042
+ if (signCentralDirectory) {
7043
+ const signatureData = await signCentralDirectory(directoryArray);
7044
+ const signatureDataLength = getLength(signatureData);
7045
+ if (signatureDataLength > MAX_16_BITS) {
7046
+ throw new Error(ERR_INVALID_SIGNATURE_DATA);
7047
+ }
7048
+ const signatureRecord = createRecordWriter(6 + signatureDataLength);
7049
+ signatureRecord.uint32(DIGITAL_SIGNATURE_RECORD_SIGNATURE);
7050
+ signatureRecord.uint16(signatureDataLength);
7051
+ signatureRecord.bytes(signatureData);
7052
+ await writeData(zipWriter.writer, signatureRecord.array);
7053
+ return 6 + signatureDataLength;
7054
+ }
7055
+ return 0;
6975
7056
  }
6976
7057
 
6977
7058
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
6978
7059
  const { writer } = zipWriter;
6979
- const { directoryStart } = cdInfo;
7060
+ const { directoryStart, signatureLength } = cdInfo;
6980
7061
  let { directoryDataLength } = cdInfo;
6981
7062
  let filesLength = zipWriter.files.size;
6982
7063
  let diskNumber = directoryStart.diskNumber;
@@ -7015,7 +7096,7 @@
7015
7096
  endOfdirectoryRecord.uint64(directoryOffset);
7016
7097
  endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
7017
7098
  endOfdirectoryRecord.uint32(lastDiskNumber);
7018
- endOfdirectoryRecord.uint64(BigInt(getSegmentOffset(zipWriter, writer)) + BigInt(directoryDataLength));
7099
+ endOfdirectoryRecord.uint64(BigInt(getSegmentOffset(zipWriter, writer)) + BigInt(directoryDataLength) + BigInt(signatureLength));
7019
7100
  endOfdirectoryRecord.uint32(lastDiskNumber + 1);
7020
7101
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
7021
7102
  if (supportZip64SplitFile) {
@@ -7368,7 +7449,7 @@
7368
7449
  await Promise.all([initStream(reader), initStream(writer, uncompressedSize)]);
7369
7450
  const { readable } = reader;
7370
7451
  zipEntry.uncompressedSize = reader.size;
7371
- await readable.pipeTo(writer.writable);
7452
+ await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable));
7372
7453
  return writer.getData ? writer.getData() : writer.writable;
7373
7454
  }
7374
7455
  }
@@ -8288,6 +8369,8 @@
8288
8369
  }
8289
8370
  }
8290
8371
 
8372
+ exports.ERR_ENTRY_EXISTS = ERR_ENTRY_EXISTS;
8373
+ exports.ERR_READABLE_CONSUMED = ERR_READABLE_CONSUMED;
8291
8374
  exports.fs = fs;
8292
8375
 
8293
8376
  }));