@zip.js/zip.js 2.8.43 → 2.8.45

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 (56) hide show
  1. package/README.md +0 -37
  2. package/deno.json +21 -1
  3. package/dist/zip-core-external.js +194 -159
  4. package/dist/zip-core-external.min.js +1 -1
  5. package/dist/zip-core.js +194 -131
  6. package/dist/zip-core.min.js +1 -1
  7. package/dist/zip-fs-core-external.js +246 -167
  8. package/dist/zip-fs-core-external.min.js +1 -1
  9. package/dist/zip-fs-core.js +244 -139
  10. package/dist/zip-fs-core.min.js +1 -1
  11. package/dist/zip-fs-external.js +267 -1761
  12. package/dist/zip-fs-external.min.js +1 -1
  13. package/dist/zip-fs-native.js +269 -1735
  14. package/dist/zip-fs-native.min.js +1 -1
  15. package/dist/zip-fs.js +268 -1734
  16. package/dist/zip-fs.min.js +1 -1
  17. package/dist/zip-legacy.js +196 -133
  18. package/dist/zip-legacy.min.js +1 -1
  19. package/dist/zip-native.js +196 -133
  20. package/dist/zip-native.min.js +1 -1
  21. package/dist/zip-web-worker-native.js +1 -1
  22. package/dist/zip-web-worker.js +1 -1
  23. package/dist/zip.js +195 -132
  24. package/dist/zip.min.js +1 -1
  25. package/eslint.config.mjs +31 -2
  26. package/index-native.cjs +269 -1735
  27. package/index-native.min.js +1 -1
  28. package/index.cjs +268 -1734
  29. package/index.d.cts +129 -8
  30. package/index.d.ts +129 -8
  31. package/index.min.js +1 -1
  32. package/lib/core/codec-pool.js +6 -2
  33. package/lib/core/codec-worker.js +2 -2
  34. package/lib/core/constants.js +4 -0
  35. package/lib/core/options.js +6 -0
  36. package/lib/core/streams/aes-crypto-stream.js +18 -21
  37. package/lib/core/streams/codec-stream.js +6 -2
  38. package/lib/core/streams/common-crypto.js +2 -0
  39. package/lib/core/streams/zip-entry-stream.js +16 -17
  40. package/lib/core/util/mime-type-data.js +3 -0
  41. package/lib/core/util/mime-type.js +23 -1596
  42. package/lib/core/web-worker-base.js +2 -2
  43. package/lib/core/web-worker-inline-native.js +1 -1
  44. package/lib/core/web-worker-inline-wasm.js +1 -1
  45. package/lib/core/web-worker-wasm.js +4 -8
  46. package/lib/core/zip-entry.js +11 -1
  47. package/lib/core/zip-fs.js +62 -5
  48. package/lib/core/zip-reader.js +80 -43
  49. package/lib/core/zip-writer.js +68 -45
  50. package/lib/zip-core-external.js +2 -0
  51. package/lib/zip-core-reader.js +2 -0
  52. package/lib/zip-fs-core-external.js +2 -0
  53. package/lib/zip-fs-external.js +2 -0
  54. package/lib/zip-mime-types.js +2 -0
  55. package/package.json +9 -3
  56. package/worker-message-property-names.js +1 -1
@@ -70,6 +70,8 @@
70
70
  const EXTRAFIELD_TYPE_USDZ = 0x1986;
71
71
  const EXTRAFIELD_TYPE_INFOZIP = 0x7875;
72
72
  const EXTRAFIELD_TYPE_UNIX = 0x7855;
73
+ const EXTRAFIELD_TYPE_UNIX_TYPE1 = 0x5855;
74
+ const EXTRAFIELD_TYPE_PKWARE_UNIX = 0x000d;
73
75
 
74
76
  const BITFLAG_ENCRYPTED = 0b1;
75
77
  const BITFLAG_LEVEL = 0b0110;
@@ -2315,6 +2317,7 @@
2315
2317
 
2316
2318
  const ERR_INVALID_PASSWORD = "Invalid password";
2317
2319
  const ERR_INVALID_SIGNATURE = "Invalid signature";
2320
+ const ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_SIGNATURE;
2318
2321
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
2319
2322
  const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
2320
2323
 
@@ -2365,7 +2368,7 @@
2365
2368
  const DERIVED_BITS_USAGE = ["deriveBits"];
2366
2369
  const SALT_LENGTH = [8, 12, 16];
2367
2370
  const KEY_LENGTH = [16, 24, 32];
2368
- const SIGNATURE_LENGTH = 10;
2371
+ const AUTHENTICATION_CODE_LENGTH = 10;
2369
2372
  const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0];
2370
2373
  // deno-lint-ignore valid-typeof
2371
2374
  const CRYPTO_API_SUPPORTED = typeof crypto != UNDEFINED_TYPE;
@@ -2381,7 +2384,7 @@
2381
2384
 
2382
2385
  class AESDecryptionStream extends TransformStream {
2383
2386
 
2384
- constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
2387
+ constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly, checkAuthenticationCode = true }) {
2385
2388
  super({
2386
2389
  start() {
2387
2390
  initAesCrypto(this, password, rawPassword, encryptionStrength);
@@ -2405,8 +2408,8 @@
2405
2408
  } else {
2406
2409
  await ready;
2407
2410
  }
2408
- const output = new Uint8Array(chunk.length - SIGNATURE_LENGTH - ((chunk.length - SIGNATURE_LENGTH) % BLOCK_LENGTH));
2409
- controller.enqueue(append(aesCrypto, chunk, output, 0, SIGNATURE_LENGTH, true));
2411
+ const output = new Uint8Array(chunk.length - AUTHENTICATION_CODE_LENGTH - ((chunk.length - AUTHENTICATION_CODE_LENGTH) % BLOCK_LENGTH));
2412
+ controller.enqueue(append(aesCrypto, chunk, output, 0, AUTHENTICATION_CODE_LENGTH, true));
2410
2413
  },
2411
2414
  async flush(controller) {
2412
2415
  const {
@@ -2417,8 +2420,8 @@
2417
2420
  } = this;
2418
2421
  if (hmac && ctr) {
2419
2422
  await ready;
2420
- const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
2421
- const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
2423
+ const chunkToDecrypt = subarray(pending, 0, pending.length - AUTHENTICATION_CODE_LENGTH);
2424
+ const originalAuthenticationCode = subarray(pending, pending.length - AUTHENTICATION_CODE_LENGTH);
2422
2425
  let decryptedChunkArray = EMPTY_UINT8_ARRAY;
2423
2426
  if (chunkToDecrypt.length) {
2424
2427
  const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
@@ -2426,13 +2429,13 @@
2426
2429
  const decryptedChunk = ctr.update(encryptedChunk);
2427
2430
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
2428
2431
  }
2429
- const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
2430
- let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
2431
- for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
2432
- invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
2432
+ const authenticationCode = subarray(fromBits(codecBytes, hmac.digest()), 0, AUTHENTICATION_CODE_LENGTH);
2433
+ let invalidAuthenticationCode = pending.length < AUTHENTICATION_CODE_LENGTH ? 1 : 0;
2434
+ for (let indexByte = 0; indexByte < AUTHENTICATION_CODE_LENGTH; indexByte++) {
2435
+ invalidAuthenticationCode |= authenticationCode[indexByte] ^ originalAuthenticationCode[indexByte];
2433
2436
  }
2434
- if (invalidSignature) {
2435
- throw new Error(ERR_INVALID_SIGNATURE);
2437
+ if (invalidAuthenticationCode && checkAuthenticationCode) {
2438
+ throw new Error(ERR_INVALID_AUTHENTICATION_CODE);
2436
2439
  }
2437
2440
  controller.enqueue(decryptedChunkArray);
2438
2441
  }
@@ -2444,8 +2447,6 @@
2444
2447
  class AESEncryptionStream extends TransformStream {
2445
2448
 
2446
2449
  constructor({ password, rawPassword, encryptionStrength }) {
2447
- // deno-lint-ignore prefer-const
2448
- let stream;
2449
2450
  super({
2450
2451
  start() {
2451
2452
  initAesCrypto(this, password, rawPassword, encryptionStrength);
@@ -2484,12 +2485,11 @@
2484
2485
  hmac.update(encryptedChunk);
2485
2486
  encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
2486
2487
  }
2487
- stream.signature = fromBits(codecBytes, hmac.digest()).slice(0, SIGNATURE_LENGTH);
2488
- controller.enqueue(concat(encryptedChunkArray, stream.signature));
2488
+ const authenticationCode = fromBits(codecBytes, hmac.digest()).slice(0, AUTHENTICATION_CODE_LENGTH);
2489
+ controller.enqueue(concat(encryptedChunkArray, authenticationCode));
2489
2490
  }
2490
2491
  }
2491
2492
  });
2492
- stream = this;
2493
2493
  }
2494
2494
  }
2495
2495
 
@@ -2502,7 +2502,7 @@
2502
2502
  });
2503
2503
  }
2504
2504
 
2505
- function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
2505
+ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifyAuthenticationCode) {
2506
2506
  const {
2507
2507
  ctr,
2508
2508
  hmac,
@@ -2516,11 +2516,11 @@
2516
2516
  let offset;
2517
2517
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
2518
2518
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
2519
- if (verifySignature) {
2519
+ if (verifyAuthenticationCode) {
2520
2520
  hmac.update(inputChunk);
2521
2521
  }
2522
2522
  const outputChunk = ctr.update(inputChunk);
2523
- if (!verifySignature) {
2523
+ if (!verifyAuthenticationCode) {
2524
2524
  hmac.update(outputChunk);
2525
2525
  }
2526
2526
  output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
@@ -2803,6 +2803,7 @@
2803
2803
 
2804
2804
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
2805
2805
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
2806
+ const ERR_INVALID_CRC32 = ERR_INVALID_SIGNATURE;
2806
2807
  const ERR_UNSUPPORTED_COMPRESSION$2 = "Compression method not supported";
2807
2808
  const FORMAT_DEFLATE_RAW = "deflate-raw";
2808
2809
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
@@ -2816,14 +2817,14 @@
2816
2817
 
2817
2818
  constructor(options, { chunkSize, CompressionStreamZlib, CompressionStream }) {
2818
2819
  super({});
2819
- const { compressed, encrypted, useCompressionStream, zipCrypto, signed, level, deflate64, format, compressionMethod } = options;
2820
+ const { compressed, encrypted, useCompressionStream, zipCrypto, computeCrc32, level, deflate64, format, compressionMethod } = options;
2820
2821
  const stream = this;
2821
2822
  let crc32Stream, encryptionStream, gzipCrc32Stream;
2822
2823
  let readable = super.readable;
2823
2824
  const codecStreams = format && getCodecStreams(format);
2824
- const useGzipCrc32 = signed && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
2825
+ const useGzipCrc32 = computeCrc32 && compressed && !deflate64 && !codecStreams && (!encrypted || zipCrypto) &&
2825
2826
  Boolean(useCompressionStream && CompressionStream);
2826
- if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
2827
+ if ((!encrypted || zipCrypto) && computeCrc32 && !useGzipCrc32) {
2827
2828
  crc32Stream = new Crc32Stream();
2828
2829
  readable = pipeThrough(readable, crc32Stream);
2829
2830
  }
@@ -2858,14 +2859,9 @@
2858
2859
  }
2859
2860
  }
2860
2861
  setReadable(stream, readable, () => {
2861
- let signature;
2862
- if (encrypted && !zipCrypto) {
2863
- signature = encryptionStream.signature;
2864
- }
2865
- if ((!encrypted || zipCrypto) && signed) {
2866
- signature = useGzipCrc32 ? gzipCrc32Stream.signature : new DataView(crc32Stream.value.buffer).getUint32(0);
2862
+ if ((!encrypted || zipCrypto) && computeCrc32) {
2863
+ stream.crc32 = useGzipCrc32 ? gzipCrc32Stream.crc32 : new DataView(crc32Stream.value.buffer).getUint32(0);
2867
2864
  }
2868
- stream.signature = signature;
2869
2865
  });
2870
2866
  }
2871
2867
  }
@@ -2903,7 +2899,7 @@
2903
2899
  },
2904
2900
  flush() {
2905
2901
  const dataView = getDataView(trailerCandidate);
2906
- stream.signature = dataView.getUint32(0, true);
2902
+ stream.crc32 = dataView.getUint32(0, true);
2907
2903
  stream.uncompressedSize = dataView.getUint32(4, true);
2908
2904
  }
2909
2905
  });
@@ -2985,7 +2981,7 @@
2985
2981
 
2986
2982
  constructor(options, { chunkSize, DecompressionStreamZlib, DecompressionStream }) {
2987
2983
  super({});
2988
- const { zipCrypto, encrypted, signed, signature, compressed, useCompressionStream, deflate64, format, compressionMethod, rawBitFlag, outputSize } = options;
2984
+ const { zipCrypto, encrypted, checkCrc32, crc32, compressed, useCompressionStream, deflate64, format, compressionMethod, rawBitFlag, outputSize } = options;
2989
2985
  let crc32Stream, decryptionStream;
2990
2986
  let readable = super.readable;
2991
2987
  if (encrypted) {
@@ -3018,15 +3014,15 @@
3018
3014
  }
3019
3015
  readable = mapInflateStreamError(readable);
3020
3016
  }
3021
- if ((!encrypted || zipCrypto) && signed) {
3017
+ if (checkCrc32) {
3022
3018
  crc32Stream = new Crc32Stream();
3023
3019
  readable = pipeThrough(readable, crc32Stream);
3024
3020
  }
3025
3021
  setReadable(this, readable, () => {
3026
- if ((!encrypted || zipCrypto) && signed) {
3027
- const dataViewSignature = new DataView(crc32Stream.value.buffer);
3028
- if (signature != dataViewSignature.getUint32(0, false)) {
3029
- throw new Error(ERR_INVALID_SIGNATURE);
3022
+ if (checkCrc32) {
3023
+ const computedCrc32View = new DataView(crc32Stream.value.buffer);
3024
+ if (crc32 != computedCrc32View.getUint32(0, false)) {
3025
+ throw new Error(ERR_INVALID_CRC32);
3030
3026
  }
3031
3027
  }
3032
3028
  });
@@ -3250,9 +3246,9 @@
3250
3246
  }
3251
3247
  },
3252
3248
  flush() {
3253
- const { signature } = stream;
3249
+ const { crc32 } = stream;
3254
3250
  Object.assign(codec, {
3255
- signature,
3251
+ crc32,
3256
3252
  inputSize
3257
3253
  });
3258
3254
  }
@@ -3547,12 +3543,12 @@
3547
3543
  .pipeThrough(new ChunkStream(getChunkSize(config)))
3548
3544
  .pipeTo(writable, { preventClose: true, preventAbort: true });
3549
3545
  const {
3550
- signature,
3546
+ crc32,
3551
3547
  inputSize,
3552
3548
  outputSize
3553
3549
  } = codecStream;
3554
3550
  return {
3555
- signature,
3551
+ crc32,
3556
3552
  inputSize,
3557
3553
  outputSize
3558
3554
  };
@@ -3913,7 +3909,7 @@
3913
3909
 
3914
3910
  async function runWorker(stream, workerOptions) {
3915
3911
  const { options, config } = workerOptions;
3916
- const { transferStreams, useWebWorkers, useCompressionStream, compressed, signed, encrypted, format, codecURI } = options;
3912
+ const { transferStreams, useWebWorkers, useCompressionStream, compressed, checkCrc32, computeCrc32, encrypted, format, codecURI } = options;
3917
3913
  const { workerURI, maxWorkers } = config;
3918
3914
  if (format) {
3919
3915
  if (codecURI) {
@@ -3922,7 +3918,7 @@
3922
3918
  await ensureCodecStreams(format, options.codecURI);
3923
3919
  }
3924
3920
  workerOptions.transferStreams = transferStreams || (transferStreams === UNDEFINED_VALUE && config.transferStreams);
3925
- const streamCopy = !compressed && !signed && !encrypted;
3921
+ const streamCopy = !compressed && !checkCrc32 && !computeCrc32 && !encrypted;
3926
3922
  const workerSupported = format === UNDEFINED_VALUE || Boolean(options.codecURI);
3927
3923
  workerOptions.useWebWorkers = !streamCopy && workerSupported && (useWebWorkers || (useWebWorkers === UNDEFINED_VALUE && config.useWebWorkers));
3928
3924
  workerOptions.workerURI = workerOptions.useWebWorkers && workerURI ? workerURI : UNDEFINED_VALUE;
@@ -4165,9 +4161,12 @@
4165
4161
  const PROPERTY_NAME_EXECUTABLE = "executable";
4166
4162
  const PROPERTY_NAME_COMPRESSION_METHOD = "compressionMethod";
4167
4163
  const PROPERTY_NAME_SIGNATURE = "signature";
4164
+ const PROPERTY_NAME_CRC32 = "crc32";
4168
4165
  const PROPERTY_NAME_EXTRA_FIELD = "extraField";
4169
4166
  const PROPERTY_NAME_EXTRA_FIELD_INFOZIP = "extraFieldInfoZip";
4170
4167
  const PROPERTY_NAME_EXTRA_FIELD_UNIX = "extraFieldUnix";
4168
+ const PROPERTY_NAME_EXTRA_FIELD_UNIX_TYPE1 = "extraFieldUnixType1";
4169
+ const PROPERTY_NAME_EXTRA_FIELD_PKWARE_UNIX = "extraFieldPkwareUnix";
4171
4170
  const PROPERTY_NAME_UID = "uid";
4172
4171
  const PROPERTY_NAME_GID = "gid";
4173
4172
  const PROPERTY_NAME_UNIX_MODE = "unixMode";
@@ -4184,6 +4183,7 @@
4184
4183
  const PROPERTY_NAME_EXTRA_FIELD_AES = "extraFieldAES";
4185
4184
  const PROPERTY_NAME_EXTRA_FIELD_NTFS = "extraFieldNTFS";
4186
4185
  const PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP = "extraFieldExtendedTimestamp";
4186
+ const PROPERTY_NAME_EXTRA_FIELD_USDZ = "extraFieldUSDZ";
4187
4187
 
4188
4188
  const PROPERTY_NAMES = [
4189
4189
  PROPERTY_NAME_FILENAME,
@@ -4195,6 +4195,7 @@
4195
4195
  PROPERTY_NAME_COMMENT,
4196
4196
  PROPERTY_NAME_RAW_COMMENT,
4197
4197
  PROPERTY_NAME_LAST_ACCESS_DATE,
4198
+ PROPERTY_NAME_RAW_LAST_ACCESS_DATE,
4198
4199
  PROPERTY_NAME_CREATION_DATE,
4199
4200
  PROPERTY_NAME_RAW_CREATION_DATE,
4200
4201
  PROPERTY_NAME_OFFSET,
@@ -4213,9 +4214,12 @@
4213
4214
  PROPERTY_NAME_EXECUTABLE,
4214
4215
  PROPERTY_NAME_COMPRESSION_METHOD,
4215
4216
  PROPERTY_NAME_SIGNATURE,
4217
+ PROPERTY_NAME_CRC32,
4216
4218
  PROPERTY_NAME_EXTRA_FIELD,
4217
4219
  PROPERTY_NAME_EXTRA_FIELD_UNIX,
4218
4220
  PROPERTY_NAME_EXTRA_FIELD_INFOZIP,
4221
+ PROPERTY_NAME_EXTRA_FIELD_UNIX_TYPE1,
4222
+ PROPERTY_NAME_EXTRA_FIELD_PKWARE_UNIX,
4219
4223
  PROPERTY_NAME_UID,
4220
4224
  PROPERTY_NAME_GID,
4221
4225
  PROPERTY_NAME_UNIX_MODE,
@@ -4231,7 +4235,8 @@
4231
4235
  PROPERTY_NAME_EXTRA_FIELD_UNICODE_COMMENT,
4232
4236
  PROPERTY_NAME_EXTRA_FIELD_AES,
4233
4237
  PROPERTY_NAME_EXTRA_FIELD_NTFS,
4234
- PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP
4238
+ PROPERTY_NAME_EXTRA_FIELD_EXTENDED_TIMESTAMP,
4239
+ PROPERTY_NAME_EXTRA_FIELD_USDZ
4235
4240
  ];
4236
4241
 
4237
4242
  class Entry {
@@ -4284,6 +4289,8 @@
4284
4289
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
4285
4290
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
4286
4291
  const OPTION_CHECK_SIGNATURE = "checkSignature";
4292
+ const OPTION_CHECK_CRC32 = "checkCrc32";
4293
+ const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
4287
4294
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
4288
4295
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
4289
4296
  const OPTION_TRANSFER_STREAMS = "transferStreams";
@@ -4303,6 +4310,7 @@
4303
4310
  const OPTION_OFFSET = "offset";
4304
4311
  const OPTION_USDZ = "usdz";
4305
4312
  const OPTION_UNIX_EXTRA_FIELD_TYPE = "unixExtraFieldType";
4313
+ const OPTION_LOCAL_EXTRA_FIELD = "localExtraField";
4306
4314
  const OPTION_STRICTNESS = "strictness";
4307
4315
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
4308
4316
  const STRICTNESS_STRICT = "strict";
@@ -4355,6 +4363,7 @@
4355
4363
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
4356
4364
  const CHARSET_CP437 = "cp437";
4357
4365
  const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
4366
+ const VENDOR_VERSION_AE_1$1 = 1;
4358
4367
  const ZIP64_PROPERTIES = [
4359
4368
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
4360
4369
  [PROPERTY_NAME_COMPRESSED_SIZE, MAX_32_BITS],
@@ -4707,7 +4716,7 @@
4707
4716
  config,
4708
4717
  bitFlag,
4709
4718
  rawBitFlag,
4710
- signature,
4719
+ crc32,
4711
4720
  rawLastModDate,
4712
4721
  uncompressedSize,
4713
4722
  compressedSize
@@ -4794,6 +4803,11 @@
4794
4803
  if (deflate64) {
4795
4804
  useCompressionStream = false;
4796
4805
  }
4806
+ const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
4807
+ const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
4808
+ getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
4809
+ checkCrc32Option) && !passThrough &&
4810
+ (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
4797
4811
  const workerOptions = {
4798
4812
  options: {
4799
4813
  codecType: CODEC_INFLATE,
@@ -4801,10 +4815,11 @@
4801
4815
  rawPassword,
4802
4816
  zipCrypto,
4803
4817
  encryptionStrength: extraFieldAES && extraFieldAES.strength,
4804
- signed: getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) && !passThrough,
4805
- passwordVerification: zipCrypto && (dataDescriptor ? ((rawLastModDate >>> 8) & MAX_8_BITS) : ((signature >>> 24) & MAX_8_BITS)),
4818
+ checkCrc32,
4819
+ checkAuthenticationCode: getOptionValue$1(zipEntry, options, OPTION_CHECK_AUTHENTICATION_CODE),
4820
+ passwordVerification: zipCrypto && (dataDescriptor ? ((rawLastModDate >>> 8) & MAX_8_BITS) : ((crc32 >>> 24) & MAX_8_BITS)),
4806
4821
  outputSize: passThrough ? compressedSize : uncompressedSize,
4807
- signature,
4822
+ crc32,
4808
4823
  compressed: compressionMethod != 0 && !passThrough,
4809
4824
  encrypted,
4810
4825
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
@@ -4826,7 +4841,7 @@
4826
4841
  fileEntry,
4827
4842
  index,
4828
4843
  offset: localHeaderOffset,
4829
- signature,
4844
+ crc32,
4830
4845
  compressedSize,
4831
4846
  uncompressedSize,
4832
4847
  dataOffset,
@@ -4917,6 +4932,7 @@
4917
4932
  const compressionMethod = getUint16(dataView, offset + 4);
4918
4933
  Object.assign(directory, {
4919
4934
  signature: getUint32(dataView, offset + HEADER_OFFSET_SIGNATURE),
4935
+ crc32: getUint32(dataView, offset + HEADER_OFFSET_SIGNATURE),
4920
4936
  compressedSize: getUint32(dataView, offset + HEADER_OFFSET_COMPRESSED_SIZE),
4921
4937
  uncompressedSize: getUint32(dataView, offset + HEADER_OFFSET_UNCOMPRESSED_SIZE)
4922
4938
  });
@@ -4942,6 +4958,16 @@
4942
4958
  } else {
4943
4959
  directory.compressionMethod = compressionMethod;
4944
4960
  }
4961
+ const extraFieldPkwareUnix = extraField.get(EXTRAFIELD_TYPE_PKWARE_UNIX);
4962
+ if (extraFieldPkwareUnix) {
4963
+ readExtraFieldUnixDates(extraFieldPkwareUnix, directory);
4964
+ directory.extraFieldPkwareUnix = extraFieldPkwareUnix;
4965
+ }
4966
+ const extraFieldUnixType1 = extraField.get(EXTRAFIELD_TYPE_UNIX_TYPE1);
4967
+ if (extraFieldUnixType1) {
4968
+ readExtraFieldUnixDates(extraFieldUnixType1, directory);
4969
+ directory.extraFieldUnixType1 = extraFieldUnixType1;
4970
+ }
4945
4971
  const extraFieldNTFS = extraField.get(EXTRAFIELD_TYPE_NTFS);
4946
4972
  if (extraFieldNTFS) {
4947
4973
  readExtraFieldNTFS(extraFieldNTFS, directory);
@@ -4991,15 +5017,15 @@
4991
5017
  return;
4992
5018
  }
4993
5019
  const extraFieldView = getDataView(extraFieldUnicode.data);
4994
- const crc32 = new Crc32();
4995
- crc32.append(fileEntry[rawPropertyName]);
4996
- const dataViewSignature = getDataView(new Uint8Array(4));
4997
- dataViewSignature.setUint32(0, crc32.get(), true);
4998
- const signature = getUint32(extraFieldView, 1);
5020
+ const computedCrc32 = new Crc32();
5021
+ computedCrc32.append(fileEntry[rawPropertyName]);
5022
+ const computedCrc32View = getDataView(new Uint8Array(4));
5023
+ computedCrc32View.setUint32(0, computedCrc32.get(), true);
5024
+ const nameCrc32 = getUint32(extraFieldView, 1);
4999
5025
  Object.assign(extraFieldUnicode, {
5000
5026
  version: getUint8(extraFieldView, 0),
5001
5027
  [propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
5002
- valid: !fileEntry.bitFlag.languageEncodingFlag && signature == getUint32(dataViewSignature, 0)
5028
+ valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32(computedCrc32View, 0)
5003
5029
  });
5004
5030
  if (extraFieldUnicode.valid) {
5005
5031
  directory[propertyName] = extraFieldUnicode[propertyName];
@@ -5018,6 +5044,9 @@
5018
5044
  compressionMethod: getUint16(extraFieldView, 5)
5019
5045
  });
5020
5046
  directory.compressionMethod = extraFieldAES.compressionMethod;
5047
+ if (extraFieldAES.vendorVersion != VENDOR_VERSION_AE_1$1) {
5048
+ directory.crc32 = UNDEFINED_VALUE;
5049
+ }
5021
5050
  }
5022
5051
 
5023
5052
  function readExtraFieldNTFS(extraFieldNTFS, directory) {
@@ -5036,29 +5065,41 @@
5036
5065
  } catch {
5037
5066
  // ignored
5038
5067
  }
5039
- try {
5040
- if (tag1Data && tag1Data.length == 24) {
5041
- const tag1View = getDataView(tag1Data);
5042
- const rawLastModDate = tag1View.getBigUint64(0, true);
5043
- const rawLastAccessDate = tag1View.getBigUint64(8, true);
5044
- const rawCreationDate = tag1View.getBigUint64(16, true);
5045
- Object.assign(extraFieldNTFS, {
5046
- rawLastModDate,
5047
- rawLastAccessDate,
5048
- rawCreationDate
5049
- });
5050
- const lastModDate = getDateNTFS(rawLastModDate);
5051
- const lastAccessDate = getDateNTFS(rawLastAccessDate);
5052
- const creationDate = getDateNTFS(rawCreationDate);
5053
- const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5054
- Object.assign(extraFieldNTFS, extraFieldData);
5055
- Object.assign(directory, extraFieldData);
5056
- }
5057
- } catch {
5058
- // ignored
5068
+ if (tag1Data && tag1Data.length == 24) {
5069
+ const tag1View = getDataView(tag1Data);
5070
+ const rawLastModDate = tag1View.getBigUint64(0, true);
5071
+ const rawLastAccessDate = tag1View.getBigUint64(8, true);
5072
+ const rawCreationDate = tag1View.getBigUint64(16, true);
5073
+ Object.assign(extraFieldNTFS, {
5074
+ rawLastModDate,
5075
+ rawLastAccessDate,
5076
+ rawCreationDate
5077
+ });
5078
+ const lastModDate = getDateNTFS(rawLastModDate);
5079
+ const lastAccessDate = getDateNTFS(rawLastAccessDate);
5080
+ const creationDate = getDateNTFS(rawCreationDate);
5081
+ const extraFieldData = { lastModDate, lastAccessDate, creationDate };
5082
+ Object.assign(extraFieldNTFS, extraFieldData);
5083
+ Object.assign(directory, extraFieldData);
5059
5084
  }
5060
5085
  }
5061
5086
 
5087
+ function readExtraFieldUnixDates(extraField, directory) {
5088
+ if (extraField.data.length < 8) {
5089
+ return;
5090
+ }
5091
+ const extraFieldView = getDataView(extraField.data);
5092
+ const lastAccessDate = new Date(getUint32(extraFieldView, 0) * 1000);
5093
+ const lastModDate = new Date(getUint32(extraFieldView, 4) * 1000);
5094
+ const extraFieldData = { lastAccessDate, lastModDate };
5095
+ if (extraField.data.length >= 12) {
5096
+ extraFieldData.uid = getUint16(extraFieldView, 8);
5097
+ extraFieldData.gid = getUint16(extraFieldView, 10);
5098
+ }
5099
+ Object.assign(extraField, extraFieldData);
5100
+ Object.assign(directory, extraFieldData);
5101
+ }
5102
+
5062
5103
  function readExtraFieldUnix(extraField, directory, isInfoZip) {
5063
5104
  try {
5064
5105
  const view = getDataView(extraField.data);
@@ -5137,7 +5178,7 @@
5137
5178
  fileEntry,
5138
5179
  index,
5139
5180
  offset,
5140
- signature,
5181
+ crc32,
5141
5182
  compressedSize,
5142
5183
  uncompressedSize,
5143
5184
  dataOffset,
@@ -5158,7 +5199,7 @@
5158
5199
  const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
5159
5200
  getUint32(getDataView(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
5160
5201
  if (dataDescriptorSignature) {
5161
- const readSignature = getUint32(getDataView(dataDescriptorArray), 4);
5202
+ const readCrc32 = getUint32(getDataView(dataDescriptorArray), 4);
5162
5203
  let readCompressedSize;
5163
5204
  let readUncompressedSize;
5164
5205
  if (extraFieldZip64) {
@@ -5168,8 +5209,8 @@
5168
5209
  readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
5169
5210
  readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
5170
5211
  }
5171
- const matchSignature = (fileEntry.encrypted && !fileEntry.zipCrypto) || readSignature == signature;
5172
- if (matchSignature &&
5212
+ const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
5213
+ if (matchCrc32 &&
5173
5214
  readCompressedSize == compressedSize &&
5174
5215
  readUncompressedSize == uncompressedSize) {
5175
5216
  dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
@@ -5338,11 +5379,11 @@
5338
5379
  throwAmbiguousArchive("mismatched local file header (compression method)");
5339
5380
  }
5340
5381
  if (!localDirectory.bitFlag.dataDescriptor &&
5341
- (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
5342
- (localDirectory.signature != zipEntry.signature ||
5382
+ (localDirectory.crc32 || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
5383
+ (localDirectory.crc32 != zipEntry.crc32 ||
5343
5384
  localDirectory.compressedSize != zipEntry.compressedSize ||
5344
5385
  localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
5345
- throwAmbiguousArchive("mismatched local file header (signature or sizes)");
5386
+ throwAmbiguousArchive("mismatched local file header (crc32 or sizes)");
5346
5387
  }
5347
5388
  }
5348
5389
 
@@ -5358,11 +5399,7 @@
5358
5399
 
5359
5400
  function getDate(timeRaw) {
5360
5401
  const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
5361
- try {
5362
- return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
5363
- } catch {
5364
- // ignored
5365
- }
5402
+ return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
5366
5403
  }
5367
5404
 
5368
5405
  function getDateNTFS(timeRaw) {
@@ -5395,7 +5432,9 @@
5395
5432
  ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND: ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND,
5396
5433
  ERR_EOCDR_NOT_FOUND: ERR_EOCDR_NOT_FOUND,
5397
5434
  ERR_EXTRAFIELD_ZIP64_NOT_FOUND: ERR_EXTRAFIELD_ZIP64_NOT_FOUND,
5435
+ ERR_INVALID_AUTHENTICATION_CODE: ERR_INVALID_AUTHENTICATION_CODE,
5398
5436
  ERR_INVALID_COMPRESSED_DATA: ERR_INVALID_COMPRESSED_DATA,
5437
+ ERR_INVALID_CRC32: ERR_INVALID_CRC32,
5399
5438
  ERR_INVALID_PASSWORD: ERR_INVALID_PASSWORD,
5400
5439
  ERR_INVALID_SIGNATURE: ERR_INVALID_SIGNATURE,
5401
5440
  ERR_INVALID_UNCOMPRESSED_SIZE: ERR_INVALID_UNCOMPRESSED_SIZE,
@@ -5448,6 +5487,8 @@
5448
5487
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
5449
5488
  const MIN_UNIX_TIME = -2147483648;
5450
5489
  const MAX_UNIX_TIME = 2147483647;
5490
+ const MIN_NTFS_TIME = BigInt(0);
5491
+ const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
5451
5492
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
5452
5493
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
5453
5494
  const ERR_UNDEFINED_READER = "Undefined reader";
@@ -5461,7 +5502,9 @@
5461
5502
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
5462
5503
 
5463
5504
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
5464
- const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
5505
+ const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
5506
+ const VENDOR_VERSION_AE_1 = 1;
5507
+ const INFOZIP_EXTRA_FIELD_TYPE$1 = "infozip";
5465
5508
  const UNIX_EXTRA_FIELD_TYPE = "unix";
5466
5509
 
5467
5510
  let workers = 0;
@@ -5555,9 +5598,9 @@
5555
5598
  zip64UncompressedSize,
5556
5599
  extraFieldLength
5557
5600
  });
5558
- const { signature } = entry;
5559
- if (signature !== UNDEFINED_VALUE) {
5560
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
5601
+ const { crc32 } = entry;
5602
+ if (crc32 !== UNDEFINED_VALUE) {
5603
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
5561
5604
  }
5562
5605
  Object.assign(entry, {
5563
5606
  zip64UncompressedSize,
@@ -5680,6 +5723,7 @@
5680
5723
  internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
5681
5724
  externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
5682
5725
  signature: options[PROPERTY_NAME_SIGNATURE],
5726
+ crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
5683
5727
  offset: zipWriter.offset - diskOffset,
5684
5728
  diskNumberStart: diskNumber
5685
5729
  });
@@ -5716,7 +5760,7 @@
5716
5760
  if (unixMode !== UNDEFINED_VALUE && (unixMode < 0 || unixMode > MAX_16_BITS)) {
5717
5761
  throw new Error(ERR_INVALID_UNIX_MODE);
5718
5762
  }
5719
- if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
5763
+ if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE$1 && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
5720
5764
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
5721
5765
  }
5722
5766
  if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
@@ -5724,7 +5768,7 @@
5724
5768
  throw new Error(ERR_INVALID_UNIX_ID_SIZE);
5725
5769
  }
5726
5770
  if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5727
- unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
5771
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE$1;
5728
5772
  }
5729
5773
  let msdosAttributesRaw = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
5730
5774
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
@@ -5896,27 +5940,8 @@
5896
5940
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
5897
5941
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
5898
5942
  }
5899
- let rawExtraField = EMPTY_UINT8_ARRAY;
5900
- const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
5901
- if (extraField) {
5902
- let extraFieldSize = 0;
5903
- let offset = 0;
5904
- extraField.forEach(data => extraFieldSize += 4 + getLength(data));
5905
- rawExtraField = new Uint8Array(extraFieldSize);
5906
- const rawExtraFieldView = getDataView(rawExtraField);
5907
- extraField.forEach((data, type) => {
5908
- if (type > MAX_16_BITS) {
5909
- throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
5910
- }
5911
- if (getLength(data) > MAX_16_BITS) {
5912
- throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5913
- }
5914
- setUint16(rawExtraFieldView, offset, type);
5915
- setUint16(rawExtraFieldView, offset + 2, getLength(data));
5916
- arraySet(rawExtraField, data, offset + 4);
5917
- offset += 4 + getLength(data);
5918
- });
5919
- }
5943
+ const rawExtraField = serializeExtraField(options[PROPERTY_NAME_EXTRA_FIELD]);
5944
+ const rawLocalExtraField = serializeExtraField(options[OPTION_LOCAL_EXTRA_FIELD]);
5920
5945
  return {
5921
5946
  comment,
5922
5947
  resolvedOptions: {
@@ -5950,11 +5975,36 @@
5950
5975
  useCompressionStream,
5951
5976
  dataDescriptor,
5952
5977
  zip64,
5953
- rawExtraField
5978
+ rawExtraField,
5979
+ rawLocalExtraField
5954
5980
  }
5955
5981
  };
5956
5982
  }
5957
5983
 
5984
+ function serializeExtraField(extraField) {
5985
+ if (!extraField) {
5986
+ return EMPTY_UINT8_ARRAY;
5987
+ }
5988
+ let extraFieldSize = 0;
5989
+ let offset = 0;
5990
+ extraField.forEach(data => extraFieldSize += 4 + getLength(data));
5991
+ const rawExtraField = new Uint8Array(extraFieldSize);
5992
+ const rawExtraFieldView = getDataView(rawExtraField);
5993
+ extraField.forEach((data, type) => {
5994
+ if (type > MAX_16_BITS) {
5995
+ throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
5996
+ }
5997
+ if (getLength(data) > MAX_16_BITS) {
5998
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5999
+ }
6000
+ setUint16(rawExtraFieldView, offset, type);
6001
+ setUint16(rawExtraFieldView, offset + 2, getLength(data));
6002
+ arraySet(rawExtraField, data, offset + 4);
6003
+ offset += 4 + getLength(data);
6004
+ });
6005
+ return rawExtraField;
6006
+ }
6007
+
5958
6008
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5959
6009
  const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5960
6010
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
@@ -6279,7 +6329,7 @@
6279
6329
  msdosAttributes
6280
6330
  };
6281
6331
  let {
6282
- signature,
6332
+ crc32,
6283
6333
  uncompressedSize
6284
6334
  } = options;
6285
6335
  let compressedSize = 0;
@@ -6299,7 +6349,7 @@
6299
6349
  encryptionStrength,
6300
6350
  zipCrypto: encrypted && zipCrypto,
6301
6351
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
6302
- signed: !passThrough,
6352
+ computeCrc32: !passThrough,
6303
6353
  compressed: compressed && !passThrough,
6304
6354
  encrypted: encrypted && !passThrough,
6305
6355
  useWebWorkers,
@@ -6318,7 +6368,9 @@
6318
6368
  writer.size += compressedSize;
6319
6369
  if (!passThrough) {
6320
6370
  uncompressedSize = result.inputSize;
6321
- signature = result.signature;
6371
+ if (!encrypted || zipCrypto) {
6372
+ crc32 = result.crc32;
6373
+ }
6322
6374
  }
6323
6375
  if ((!zip64CompressedSize && compressedSize >= MAX_32_BITS) ||
6324
6376
  (!zip64UncompressedSize && uncompressedSize >= MAX_32_BITS)) {
@@ -6333,7 +6385,7 @@
6333
6385
 
6334
6386
  }
6335
6387
  setEntryInfo({
6336
- signature,
6388
+ crc32,
6337
6389
  compressedSize,
6338
6390
  uncompressedSize,
6339
6391
  headerInfo,
@@ -6356,7 +6408,8 @@
6356
6408
  version,
6357
6409
  headerArray,
6358
6410
  headerView,
6359
- signature,
6411
+ signature: crc32,
6412
+ crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
6360
6413
  extraFieldExtendedTimestampFlag,
6361
6414
  zip64UncompressedSize,
6362
6415
  zip64CompressedSize
@@ -6377,6 +6430,7 @@
6377
6430
  dataDescriptor,
6378
6431
  directory,
6379
6432
  rawExtraField,
6433
+ rawLocalExtraField,
6380
6434
  encryptionStrength,
6381
6435
  extendedTimestamp,
6382
6436
  ntfsTimestamp,
@@ -6384,7 +6438,8 @@
6384
6438
  encrypted,
6385
6439
  zip64UncompressedSize,
6386
6440
  zip64CompressedSize,
6387
- uncompressedSize
6441
+ uncompressedSize,
6442
+ crc32
6388
6443
  } = options;
6389
6444
  let { version, compressionMethod } = options;
6390
6445
  const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
@@ -6457,8 +6512,8 @@
6457
6512
  extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
6458
6513
  extraFieldNTFS.uint16(24);
6459
6514
  extraFieldNTFS.uint64(lastModTimeNTFS);
6460
- extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
6461
- extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
6515
+ extraFieldNTFS.uint64(lastAccessDate ? getTimeNTFS(lastAccessDate) : lastModTimeNTFS);
6516
+ extraFieldNTFS.uint64(creationDate ? getTimeNTFS(creationDate) : lastModTimeNTFS);
6462
6517
  rawExtraFieldNTFS = extraFieldNTFS.array;
6463
6518
  } catch {
6464
6519
  rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
@@ -6472,7 +6527,7 @@
6472
6527
  let rawExtraFieldUnix;
6473
6528
  try {
6474
6529
  const { uid, gid, unixExtraFieldType } = options;
6475
- if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
6530
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE$1 && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
6476
6531
  const uidBytes = packUnixId(uid);
6477
6532
  const gidBytes = packUnixId(gid);
6478
6533
  const payloadLength = 3 + uidBytes.length + gidBytes.length;
@@ -6510,15 +6565,18 @@
6510
6565
  }
6511
6566
  if (encrypted && !zipCrypto) {
6512
6567
  version = version > VERSION_AES ? version : VERSION_AES;
6568
+ if (passThrough && crc32 !== UNDEFINED_VALUE) {
6569
+ rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
6570
+ }
6513
6571
  rawExtraFieldAES[9] = compressionMethod;
6514
6572
  compressionMethod = COMPRESSION_METHOD_AES;
6515
6573
  }
6516
6574
  const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
6517
- const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
6575
+ const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField, rawLocalExtraField);
6518
6576
  if (extraFieldLength > MAX_16_BITS) {
6519
6577
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6520
6578
  }
6521
- const dosLastModDate = new Date(Math.ceil(lastModDate.getTime() / 2000) * 2000);
6579
+ const dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
6522
6580
  const {
6523
6581
  headerArray,
6524
6582
  headerView,
@@ -6548,6 +6606,7 @@
6548
6606
  localHeader.bytes(rawExtraFieldNTFS);
6549
6607
  localHeader.bytes(rawExtraFieldUnix);
6550
6608
  localHeader.bytes(rawExtraField);
6609
+ localHeader.bytes(rawLocalExtraField);
6551
6610
  if (dataDescriptor) {
6552
6611
  if (!zip64CompressedSize) {
6553
6612
  setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
@@ -6666,7 +6725,7 @@
6666
6725
  }
6667
6726
 
6668
6727
  function setEntryInfo({
6669
- signature,
6728
+ crc32,
6670
6729
  compressedSize,
6671
6730
  uncompressedSize,
6672
6731
  headerInfo,
@@ -6674,6 +6733,7 @@
6674
6733
  }, {
6675
6734
  zip64,
6676
6735
  zipCrypto,
6736
+ passThrough,
6677
6737
  dataDescriptor
6678
6738
  }) {
6679
6739
  const {
@@ -6684,10 +6744,10 @@
6684
6744
  dataDescriptorView,
6685
6745
  dataDescriptorOffset
6686
6746
  } = dataDescriptorInfo;
6687
- if ((!encrypted || zipCrypto) && signature !== UNDEFINED_VALUE) {
6688
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
6747
+ if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
6748
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6689
6749
  if (dataDescriptor) {
6690
- setUint32(dataDescriptorView, dataDescriptorOffset, signature);
6750
+ setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
6691
6751
  }
6692
6752
  }
6693
6753
  if (zip64) {
@@ -6710,15 +6770,15 @@
6710
6770
  encrypted,
6711
6771
  zip64,
6712
6772
  localExtraFieldZip64Length,
6713
- signature,
6773
+ crc32,
6714
6774
  compressedSize,
6715
6775
  uncompressedSize,
6716
6776
  zip64UncompressedSize,
6717
6777
  zip64CompressedSize
6718
- }, localHeaderView, { dataDescriptor }) {
6778
+ }, localHeaderView, { dataDescriptor, passThrough }) {
6719
6779
  if (!dataDescriptor) {
6720
- if (!encrypted) {
6721
- setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, signature);
6780
+ if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
6781
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
6722
6782
  }
6723
6783
  if (!zip64CompressedSize) {
6724
6784
  setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, compressedSize);
@@ -7027,7 +7087,8 @@
7027
7087
 
7028
7088
  function getTimeNTFS(date) {
7029
7089
  if (date) {
7030
- return ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
7090
+ const timeNTFS = ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
7091
+ return timeNTFS < MIN_NTFS_TIME ? MIN_NTFS_TIME : timeNTFS > MAX_NTFS_TIME ? MAX_NTFS_TIME : timeNTFS;
7031
7092
  }
7032
7093
  }
7033
7094
 
@@ -7182,6 +7243,20 @@
7182
7243
 
7183
7244
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
7184
7245
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
7246
+ const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
7247
+ const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
7248
+ EXTRAFIELD_TYPE_ZIP64,
7249
+ EXTRAFIELD_TYPE_AES,
7250
+ EXTRAFIELD_TYPE_NTFS,
7251
+ EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
7252
+ EXTRAFIELD_TYPE_UNICODE_PATH,
7253
+ EXTRAFIELD_TYPE_UNICODE_COMMENT,
7254
+ EXTRAFIELD_TYPE_USDZ,
7255
+ EXTRAFIELD_TYPE_INFOZIP,
7256
+ EXTRAFIELD_TYPE_UNIX,
7257
+ EXTRAFIELD_TYPE_UNIX_TYPE1,
7258
+ EXTRAFIELD_TYPE_PKWARE_UNIX
7259
+ ]);
7185
7260
 
7186
7261
  class ZipEntry {
7187
7262
 
@@ -7919,6 +7994,20 @@
7919
7994
  }
7920
7995
  }
7921
7996
 
7997
+ function getUserExtraField(extraField) {
7998
+ if (extraField) {
7999
+ const userExtraField = new Map();
8000
+ extraField.forEach((field, type) => {
8001
+ if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
8002
+ userExtraField.set(type, field.data);
8003
+ }
8004
+ });
8005
+ if (userExtraField.size) {
8006
+ return userExtraField;
8007
+ }
8008
+ }
8009
+ }
8010
+
7922
8011
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
7923
8012
  const selectedEntry = entry;
7924
8013
  const entryOffsets = new Map();
@@ -7956,9 +8045,13 @@
7956
8045
  uncompressedSize,
7957
8046
  encrypted,
7958
8047
  zipCrypto,
7959
- signature,
8048
+ crc32,
7960
8049
  compressionMethod,
7961
- extraFieldAES
8050
+ extraFieldAES,
8051
+ internalFileAttributes,
8052
+ extraField,
8053
+ uid,
8054
+ gid
7962
8055
  } = child.data;
7963
8056
  zipEntryOptions = {
7964
8057
  externalFileAttributes,
@@ -7966,8 +8059,20 @@
7966
8059
  comment,
7967
8060
  lastModDate,
7968
8061
  creationDate,
7969
- lastAccessDate
8062
+ lastAccessDate,
8063
+ internalFileAttributes
7970
8064
  };
8065
+ const userExtraField = getUserExtraField(extraField);
8066
+ if (userExtraField) {
8067
+ zipEntryOptions.extraField = userExtraField;
8068
+ }
8069
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
8070
+ Object.assign(zipEntryOptions, {
8071
+ uid,
8072
+ gid,
8073
+ unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
8074
+ });
8075
+ }
7971
8076
  if (child.passThrough) {
7972
8077
  let level, encryptionStrength;
7973
8078
  if (compressionMethod === 0) {
@@ -7980,7 +8085,7 @@
7980
8085
  passThrough: true,
7981
8086
  encrypted,
7982
8087
  zipCrypto,
7983
- signature,
8088
+ crc32,
7984
8089
  uncompressedSize,
7985
8090
  level,
7986
8091
  encryptionStrength,