@zip.js/zip.js 2.16.0 → 2.17.0
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.
- package/deno.json +1 -1
- package/dist/zip-core-external.js +429 -274
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +230 -151
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +580 -283
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +383 -160
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +580 -283
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +386 -163
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +583 -283
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +232 -153
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +233 -154
- package/dist/zip-native.min.js +1 -1
- package/dist/zip-web-worker-native.js +1 -1
- package/dist/zip-web-worker.js +1 -1
- package/dist/zip.js +430 -274
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -1
- package/index-native.cjs +386 -163
- package/index-native.min.js +1 -1
- package/index.cjs +583 -283
- package/index.d.cts +168 -29
- package/index.d.ts +168 -29
- package/index.min.js +1 -1
- package/lib/core/codec-pool.js +2 -0
- package/lib/core/codec-worker-web.js +11 -3
- package/lib/core/codec-worker.js +2 -1
- package/lib/core/streams/aes-crypto-stream.js +60 -17
- package/lib/core/streams/codec-stream.js +2 -0
- package/lib/core/streams/zip-crypto-stream.js +7 -7
- package/lib/core/streams/zip-entry-stream.js +130 -113
- package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
- package/lib/core/streams/zlib-wasm/zlib-streams.js +199 -122
- package/lib/core/util/compatible-streams.js +10 -5
- package/lib/core/version.js +1 -1
- package/lib/core/web-worker-base.js +1 -1
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-fs.js +157 -10
- package/lib/core/zip-reader.js +8 -5
- package/lib/core/zip-writer.js +5 -2
- package/lib/zip-core-reader.js +1 -0
- package/package.json +3 -2
package/dist/zip-fs-core.js
CHANGED
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
|
|
224
224
|
const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
|
|
225
225
|
const ERR_ABORTED = "The operation was aborted";
|
|
226
|
-
const ABORT_ERROR_NAME = "AbortError";
|
|
226
|
+
const ABORT_ERROR_NAME$1 = "AbortError";
|
|
227
227
|
|
|
228
228
|
function checkFunctionOption(value) {
|
|
229
229
|
if (value && typeof value != FUNCTION_TYPE) {
|
|
@@ -241,7 +241,7 @@
|
|
|
241
241
|
|
|
242
242
|
function throwIfAborted(signal) {
|
|
243
243
|
if (signal && signal.aborted) {
|
|
244
|
-
throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
|
|
244
|
+
throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME$1) : signal.reason;
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
@@ -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(
|
|
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
|
-
} =
|
|
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
|
-
|
|
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(
|
|
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
|
-
} =
|
|
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(
|
|
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
|
|
1639
|
+
const cryptoKeys = [0x12345678, 0x23456789, 0x34567890];
|
|
1596
1640
|
Object.assign(target, {
|
|
1597
|
-
|
|
1598
|
-
crcKey0: new Crc32(
|
|
1599
|
-
crcKey2: new Crc32(
|
|
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.
|
|
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.
|
|
1663
|
+
target.cryptoKeys = [key0, key1, key2];
|
|
1620
1664
|
}
|
|
1621
1665
|
|
|
1622
1666
|
function getByte(target) {
|
|
1623
|
-
const temp = target.
|
|
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
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
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) {
|
|
@@ -1851,7 +1900,9 @@
|
|
|
1851
1900
|
|
|
1852
1901
|
const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
|
|
1853
1902
|
const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
|
|
1903
|
+
const ERR_CODEC_OUT_OF_MEMORY = "Codec out of memory";
|
|
1854
1904
|
const ERR_INVALID_CRC32 = "Invalid CRC32";
|
|
1905
|
+
const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
|
|
1855
1906
|
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
|
1856
1907
|
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
1857
1908
|
const FORMAT_GZIP = "gzip";
|
|
@@ -1886,13 +1937,13 @@
|
|
|
1886
1937
|
readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamFallback);
|
|
1887
1938
|
} catch (error) {
|
|
1888
1939
|
if (!useCompressionStream && CompressionStreamFallback) {
|
|
1889
|
-
throw error;
|
|
1940
|
+
throw mapMemoryError(error);
|
|
1890
1941
|
}
|
|
1891
1942
|
let gzipStream;
|
|
1892
1943
|
try {
|
|
1893
1944
|
gzipStream = new CompressionStream(FORMAT_GZIP);
|
|
1894
1945
|
} catch {
|
|
1895
|
-
throw error;
|
|
1946
|
+
throw mapMemoryError(error);
|
|
1896
1947
|
}
|
|
1897
1948
|
readable = pipeThroughBackpressured(readable, gzipStream);
|
|
1898
1949
|
readable = pipeThrough(readable, new GzipToRawDeflateStream());
|
|
@@ -1956,53 +2007,30 @@
|
|
|
1956
2007
|
}
|
|
1957
2008
|
}
|
|
1958
2009
|
|
|
1959
|
-
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32) {
|
|
2010
|
+
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors) {
|
|
1960
2011
|
const writer = gzipStream.writable.getWriter();
|
|
1961
2012
|
const reader = gzipStream.readable.getReader();
|
|
1962
2013
|
const outputCrc32 = crc32 === UNDEFINED_VALUE ? new Crc32() : UNDEFINED_VALUE;
|
|
1963
2014
|
let outputLength = 0;
|
|
1964
|
-
let inputDone = false;
|
|
1965
2015
|
let trailerWritten = false;
|
|
1966
|
-
let
|
|
1967
|
-
let
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
trailerReady.catch(() => { });
|
|
1975
|
-
pump();
|
|
1976
|
-
return new ReadableStream({
|
|
1977
|
-
async pull(controller) {
|
|
1978
|
-
let result;
|
|
1979
|
-
try {
|
|
1980
|
-
result = await read();
|
|
1981
|
-
} catch (error) {
|
|
1982
|
-
throw trailerWritten ? getTrailerError(error) : error;
|
|
1983
|
-
}
|
|
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
|
-
}
|
|
2016
|
+
let settled = false;
|
|
2017
|
+
let resolvePull, controller;
|
|
2018
|
+
const output = new ReadableStream({
|
|
2019
|
+
start(streamController) {
|
|
2020
|
+
controller = streamController;
|
|
2021
|
+
},
|
|
2022
|
+
pull() {
|
|
2023
|
+
resumePump();
|
|
2000
2024
|
},
|
|
2001
2025
|
cancel(reason) {
|
|
2002
|
-
|
|
2026
|
+
settled = true;
|
|
2027
|
+
resumePump();
|
|
2003
2028
|
return reader.cancel(reason);
|
|
2004
2029
|
}
|
|
2005
2030
|
});
|
|
2031
|
+
pump();
|
|
2032
|
+
drain();
|
|
2033
|
+
return output;
|
|
2006
2034
|
|
|
2007
2035
|
async function pump() {
|
|
2008
2036
|
const inputReader = readable.getReader();
|
|
@@ -2011,19 +2039,16 @@
|
|
|
2011
2039
|
header.set(GZIP_HEADER_BYTES);
|
|
2012
2040
|
await writer.write(header);
|
|
2013
2041
|
for (; ;) {
|
|
2042
|
+
await outputCapacity();
|
|
2014
2043
|
await writer.ready;
|
|
2015
|
-
const { value, done } = await inputReader
|
|
2044
|
+
const { value, done } = await readSource(inputReader, sourceErrors);
|
|
2016
2045
|
if (done) {
|
|
2017
2046
|
break;
|
|
2018
2047
|
}
|
|
2019
2048
|
await writer.write(value);
|
|
2020
2049
|
}
|
|
2021
|
-
inputDone = true;
|
|
2022
2050
|
if (outputCrc32) {
|
|
2023
|
-
|
|
2024
|
-
armIdleCheck();
|
|
2025
|
-
}
|
|
2026
|
-
await trailerReady;
|
|
2051
|
+
await writer.write(new Uint8Array(0));
|
|
2027
2052
|
}
|
|
2028
2053
|
const trailer = new Uint8Array(GZIP_TRAILER_LENGTH);
|
|
2029
2054
|
const dataView = getDataView(trailer);
|
|
@@ -2038,54 +2063,68 @@
|
|
|
2038
2063
|
}
|
|
2039
2064
|
}
|
|
2040
2065
|
|
|
2041
|
-
function
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2066
|
+
async function drain() {
|
|
2067
|
+
try {
|
|
2068
|
+
for (; ;) {
|
|
2069
|
+
const { value, done } = await read();
|
|
2070
|
+
if (done) {
|
|
2071
|
+
break;
|
|
2072
|
+
}
|
|
2073
|
+
outputLength += value.length;
|
|
2074
|
+
if (outputLength > outputSize) {
|
|
2075
|
+
throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
2076
|
+
}
|
|
2077
|
+
if (outputCrc32) {
|
|
2078
|
+
outputCrc32.append(value);
|
|
2079
|
+
}
|
|
2080
|
+
controller.enqueue(value);
|
|
2081
|
+
}
|
|
2082
|
+
if (!settled) {
|
|
2083
|
+
settled = true;
|
|
2084
|
+
controller.close();
|
|
2085
|
+
}
|
|
2086
|
+
} catch (error) {
|
|
2087
|
+
fail(error);
|
|
2088
|
+
await cancel(reader, error);
|
|
2048
2089
|
}
|
|
2049
|
-
return result;
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
function onReadSettled() {
|
|
2053
|
-
readPending = false;
|
|
2054
2090
|
}
|
|
2055
2091
|
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
resolveTrailerReady();
|
|
2065
|
-
} else {
|
|
2066
|
-
armIdleCheck();
|
|
2092
|
+
function read() {
|
|
2093
|
+
return reader.read().catch(error => {
|
|
2094
|
+
if (trailerWritten) {
|
|
2095
|
+
if (!outputCrc32) {
|
|
2096
|
+
throw mapError(error, ERR_INVALID_CRC32);
|
|
2097
|
+
}
|
|
2098
|
+
if (outputLength != outputSize) {
|
|
2099
|
+
throw mapError(error, ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
2067
2100
|
}
|
|
2101
|
+
return { done: true };
|
|
2068
2102
|
}
|
|
2069
|
-
|
|
2103
|
+
throw mapCodecError(error, sourceErrors);
|
|
2104
|
+
});
|
|
2070
2105
|
}
|
|
2071
2106
|
|
|
2072
|
-
function
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2107
|
+
function outputCapacity() {
|
|
2108
|
+
if (!settled && controller.desiredSize <= 0) {
|
|
2109
|
+
return new Promise(resolve => resolvePull = resolve);
|
|
2110
|
+
}
|
|
2076
2111
|
}
|
|
2077
|
-
}
|
|
2078
2112
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
port1.close();
|
|
2084
|
-
port2.close();
|
|
2113
|
+
function resumePump() {
|
|
2114
|
+
if (resolvePull) {
|
|
2115
|
+
const resolve = resolvePull;
|
|
2116
|
+
resolvePull = UNDEFINED_VALUE;
|
|
2085
2117
|
resolve();
|
|
2086
|
-
}
|
|
2087
|
-
|
|
2088
|
-
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
function fail(error) {
|
|
2122
|
+
if (!settled) {
|
|
2123
|
+
settled = true;
|
|
2124
|
+
controller.error(error);
|
|
2125
|
+
resumePump();
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2089
2128
|
}
|
|
2090
2129
|
|
|
2091
2130
|
class InflateStream extends TransformStream {
|
|
@@ -2104,11 +2143,12 @@
|
|
|
2104
2143
|
}
|
|
2105
2144
|
}
|
|
2106
2145
|
if (compressed) {
|
|
2146
|
+
const sourceErrors = new Set();
|
|
2107
2147
|
const codecStreams = format && getCodecStreams(format);
|
|
2148
|
+
let gzipStream;
|
|
2108
2149
|
if (codecStreams) {
|
|
2109
|
-
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }));
|
|
2150
|
+
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }), sourceErrors);
|
|
2110
2151
|
} else {
|
|
2111
|
-
let gzipStream;
|
|
2112
2152
|
const GzipDecompressionStream = getGzipCodecStream(useCompressionStream, DecompressionStream, DecompressionStreamFallback);
|
|
2113
2153
|
if (checkCrc32 && !deflate64 && crc32 !== UNDEFINED_VALUE && outputSize !== UNDEFINED_VALUE && GzipDecompressionStream) {
|
|
2114
2154
|
try {
|
|
@@ -2119,24 +2159,25 @@
|
|
|
2119
2159
|
}
|
|
2120
2160
|
if (!gzipStream) {
|
|
2121
2161
|
try {
|
|
2122
|
-
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback);
|
|
2162
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback, sourceErrors);
|
|
2123
2163
|
} catch (error) {
|
|
2124
2164
|
if (deflate64 || outputSize === UNDEFINED_VALUE || (!useCompressionStream && DecompressionStreamFallback)) {
|
|
2125
|
-
throw error;
|
|
2165
|
+
throw mapMemoryError(error);
|
|
2126
2166
|
}
|
|
2127
2167
|
try {
|
|
2128
2168
|
gzipStream = new DecompressionStream(FORMAT_GZIP);
|
|
2129
2169
|
} catch {
|
|
2130
|
-
throw error;
|
|
2170
|
+
throw mapMemoryError(error);
|
|
2131
2171
|
}
|
|
2132
2172
|
}
|
|
2133
2173
|
}
|
|
2134
|
-
if (gzipStream) {
|
|
2135
|
-
gzipCrc32 = true;
|
|
2136
|
-
readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32);
|
|
2137
|
-
}
|
|
2138
2174
|
}
|
|
2139
|
-
|
|
2175
|
+
if (gzipStream) {
|
|
2176
|
+
gzipCrc32 = true;
|
|
2177
|
+
readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors);
|
|
2178
|
+
} else {
|
|
2179
|
+
readable = mapInflateStreamError(readable, sourceErrors);
|
|
2180
|
+
}
|
|
2140
2181
|
}
|
|
2141
2182
|
if (checkCrc32 && !gzipCrc32) {
|
|
2142
2183
|
crc32Stream = new Crc32Stream();
|
|
@@ -2209,7 +2250,7 @@
|
|
|
2209
2250
|
}
|
|
2210
2251
|
}
|
|
2211
2252
|
|
|
2212
|
-
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback) {
|
|
2253
|
+
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback, sourceErrors) {
|
|
2213
2254
|
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
2214
2255
|
CompressionStreamNative :
|
|
2215
2256
|
CompressionStreamFallback || CompressionStreamNative;
|
|
@@ -2224,14 +2265,14 @@
|
|
|
2224
2265
|
throw error;
|
|
2225
2266
|
}
|
|
2226
2267
|
}
|
|
2227
|
-
return pipeThroughBackpressured(readable, codecStream);
|
|
2268
|
+
return pipeThroughBackpressured(readable, codecStream, sourceErrors);
|
|
2228
2269
|
}
|
|
2229
2270
|
|
|
2230
2271
|
function pipeThrough(readable, transformStream) {
|
|
2231
2272
|
return toCompatibleReadable(readable).pipeThrough(transformStream);
|
|
2232
2273
|
}
|
|
2233
2274
|
|
|
2234
|
-
function pipeThroughBackpressured(readable, transformStream) {
|
|
2275
|
+
function pipeThroughBackpressured(readable, transformStream, sourceErrors) {
|
|
2235
2276
|
const writer = transformStream.writable.getWriter();
|
|
2236
2277
|
const reader = readable.getReader();
|
|
2237
2278
|
pump();
|
|
@@ -2241,7 +2282,7 @@
|
|
|
2241
2282
|
try {
|
|
2242
2283
|
for (; ;) {
|
|
2243
2284
|
await writer.ready;
|
|
2244
|
-
const result = await reader
|
|
2285
|
+
const result = await readSource(reader, sourceErrors);
|
|
2245
2286
|
if (result.done) {
|
|
2246
2287
|
await writer.close();
|
|
2247
2288
|
break;
|
|
@@ -2271,26 +2312,49 @@
|
|
|
2271
2312
|
}
|
|
2272
2313
|
}
|
|
2273
2314
|
|
|
2274
|
-
function
|
|
2315
|
+
function readSource(reader, sourceErrors) {
|
|
2316
|
+
const result = reader.read();
|
|
2317
|
+
return sourceErrors ? result.catch(error => {
|
|
2318
|
+
sourceErrors.add(error);
|
|
2319
|
+
throw error;
|
|
2320
|
+
}) : result;
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
function mapCodecError(error, sourceErrors) {
|
|
2324
|
+
if (sourceErrors.has(error)) {
|
|
2325
|
+
return error;
|
|
2326
|
+
}
|
|
2327
|
+
return mapError(error, isMemoryError(error) ? ERR_CODEC_OUT_OF_MEMORY : ERR_INVALID_COMPRESSED_DATA);
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
function mapMemoryError(error) {
|
|
2331
|
+
return isMemoryError(error) ? mapError(error, ERR_CODEC_OUT_OF_MEMORY) : error;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
function isMemoryError(error) {
|
|
2335
|
+
return isErrorObject(error) && error.code == Z_MEM_ERROR_CODE;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
function mapError(error, message) {
|
|
2339
|
+
const mappedError = new Error(message);
|
|
2340
|
+
mappedError.cause = error;
|
|
2341
|
+
return mappedError;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
function mapInflateStreamError(readable, sourceErrors) {
|
|
2275
2345
|
const reader = readable.getReader();
|
|
2276
2346
|
return new ReadableStream({
|
|
2277
2347
|
async pull(controller) {
|
|
2278
|
-
let result;
|
|
2279
2348
|
try {
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2349
|
+
const { value, done } = await reader.read();
|
|
2350
|
+
if (done) {
|
|
2351
|
+
controller.close();
|
|
2352
|
+
} else {
|
|
2353
|
+
controller.enqueue(value);
|
|
2284
2354
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
throw
|
|
2288
|
-
}
|
|
2289
|
-
const { value, done } = result;
|
|
2290
|
-
if (done) {
|
|
2291
|
-
controller.close();
|
|
2292
|
-
} else {
|
|
2293
|
-
controller.enqueue(value);
|
|
2355
|
+
} catch (error) {
|
|
2356
|
+
await cancel(reader, error);
|
|
2357
|
+
throw mapCodecError(error, sourceErrors);
|
|
2294
2358
|
}
|
|
2295
2359
|
},
|
|
2296
2360
|
cancel(reason) {
|
|
@@ -2654,10 +2718,11 @@
|
|
|
2654
2718
|
}
|
|
2655
2719
|
codecStream = new CodecStream(options, config);
|
|
2656
2720
|
chunkStream = new ChunkStream(getChunkSize(config));
|
|
2721
|
+
const { signal } = workerOptions.streamOptions;
|
|
2657
2722
|
await readable
|
|
2658
2723
|
.pipeThrough(codecStream)
|
|
2659
2724
|
.pipeThrough(chunkStream)
|
|
2660
|
-
.pipeTo(writable, { preventClose: true, preventAbort: true });
|
|
2725
|
+
.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
|
|
2661
2726
|
const {
|
|
2662
2727
|
crc32,
|
|
2663
2728
|
inputSize,
|
|
@@ -2725,6 +2790,7 @@
|
|
|
2725
2790
|
const MODULE_WORKER_OPTIONS = { type: "module" };
|
|
2726
2791
|
const ERROR_EVENT_TYPE = "error";
|
|
2727
2792
|
const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
|
|
2793
|
+
const ABORT_EVENT_TYPE = "abort";
|
|
2728
2794
|
|
|
2729
2795
|
let webWorkerSource, webWorkerURI, webWorkerOptions;
|
|
2730
2796
|
let transferStreamsSupported = true;
|
|
@@ -2901,6 +2967,13 @@
|
|
|
2901
2967
|
Object.assign(workerData, { destinationFailed: true, destinationError: error });
|
|
2902
2968
|
}
|
|
2903
2969
|
});
|
|
2970
|
+
const { signal } = workerData.workerOptions.streamOptions;
|
|
2971
|
+
if (signal) {
|
|
2972
|
+
const onAbort = () => abortController.abort(signal.reason);
|
|
2973
|
+
const removeAbortListener = () => signal.removeEventListener(ABORT_EVENT_TYPE, onAbort);
|
|
2974
|
+
signal.addEventListener(ABORT_EVENT_TYPE, onAbort);
|
|
2975
|
+
closed.then(removeAbortListener, removeAbortListener);
|
|
2976
|
+
}
|
|
2904
2977
|
return {
|
|
2905
2978
|
writable, closed, abortPipe: () => {
|
|
2906
2979
|
aborting = true;
|
|
@@ -3163,9 +3236,6 @@
|
|
|
3163
3236
|
responseError = errorValue.value;
|
|
3164
3237
|
} else {
|
|
3165
3238
|
responseError = Object.assign(new Error(message), { stack, code, name });
|
|
3166
|
-
if (cause) {
|
|
3167
|
-
responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
|
|
3168
|
-
}
|
|
3169
3239
|
}
|
|
3170
3240
|
if (isErrorObject(responseError)) {
|
|
3171
3241
|
try {
|
|
@@ -3175,6 +3245,9 @@
|
|
|
3175
3245
|
if (codecImportFailed) {
|
|
3176
3246
|
responseError.codecImportFailed = true;
|
|
3177
3247
|
}
|
|
3248
|
+
if (cause && !isErrorObject(responseError.cause)) {
|
|
3249
|
+
responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
|
|
3250
|
+
}
|
|
3178
3251
|
if (errorValue) {
|
|
3179
3252
|
if (responseError.name !== name) {
|
|
3180
3253
|
responseError.name = name;
|
|
@@ -5366,8 +5439,8 @@
|
|
|
5366
5439
|
const passThroughCompression = Boolean(passThrough);
|
|
5367
5440
|
const passThroughEncryption = passThrough === true;
|
|
5368
5441
|
checkPasswordOption(password, rawPassword);
|
|
5369
|
-
password = password && password.length
|
|
5370
|
-
rawPassword = rawPassword && rawPassword.length
|
|
5442
|
+
password = password && password.length ? password : UNDEFINED_VALUE;
|
|
5443
|
+
rawPassword = rawPassword && rawPassword.length ? rawPassword : UNDEFINED_VALUE;
|
|
5371
5444
|
if (extraFieldAES) {
|
|
5372
5445
|
if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
|
|
5373
5446
|
throw new Error(ERR_UNSUPPORTED_COMPRESSION);
|
|
@@ -5517,6 +5590,7 @@
|
|
|
5517
5590
|
({ writable } = writer);
|
|
5518
5591
|
const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
|
|
5519
5592
|
const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
|
|
5593
|
+
throwIfAborted(signal);
|
|
5520
5594
|
if (writtenSize != outputSize) {
|
|
5521
5595
|
throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
|
|
5522
5596
|
}
|
|
@@ -6128,7 +6202,7 @@
|
|
|
6128
6202
|
async function findEndOfCentralDirectory(reader, rejectAmbiguous, maxAppendedDataSize) {
|
|
6129
6203
|
const { size } = reader;
|
|
6130
6204
|
const anchoredLength = Math.min(size, END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS);
|
|
6131
|
-
const remoteProbeBudget = {
|
|
6205
|
+
const remoteProbeBudget = { remaining: MAX_END_OF_CENTRAL_DIR_PROBES };
|
|
6132
6206
|
let endOfDirectoryInfo;
|
|
6133
6207
|
let plausibleEndOfDirectoryInfo;
|
|
6134
6208
|
let endOfDirectoryReachingEndCount = 0;
|
|
@@ -6221,8 +6295,8 @@
|
|
|
6221
6295
|
if (signatureOffset >= anchoredOffset) {
|
|
6222
6296
|
return getUint32$1(view, signatureOffset - anchoredOffset);
|
|
6223
6297
|
}
|
|
6224
|
-
if (remoteProbeBudget.
|
|
6225
|
-
remoteProbeBudget.
|
|
6298
|
+
if (remoteProbeBudget.remaining > 0) {
|
|
6299
|
+
remoteProbeBudget.remaining--;
|
|
6226
6300
|
const signatureArray = await readUint8Array(reader, signatureOffset, 4);
|
|
6227
6301
|
return getUint32$1(getDataView(signatureArray), 0);
|
|
6228
6302
|
}
|
|
@@ -6312,6 +6386,7 @@
|
|
|
6312
6386
|
ERR_AMBIGUOUS_ARCHIVE: ERR_AMBIGUOUS_ARCHIVE,
|
|
6313
6387
|
ERR_BAD_FORMAT: ERR_BAD_FORMAT,
|
|
6314
6388
|
ERR_CENTRAL_DIRECTORY_NOT_FOUND: ERR_CENTRAL_DIRECTORY_NOT_FOUND,
|
|
6389
|
+
ERR_CODEC_OUT_OF_MEMORY: ERR_CODEC_OUT_OF_MEMORY,
|
|
6315
6390
|
ERR_ENCRYPTED: ERR_ENCRYPTED,
|
|
6316
6391
|
ERR_ENCRYPTED_CENTRAL_DIRECTORY: ERR_ENCRYPTED_CENTRAL_DIRECTORY,
|
|
6317
6392
|
ERR_ENTRY_DATA_OUT_OF_BOUNDS: ERR_ENTRY_DATA_OUT_OF_BOUNDS,
|
|
@@ -7138,9 +7213,11 @@
|
|
|
7138
7213
|
const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
|
|
7139
7214
|
const passThroughCompression = Boolean(passThrough);
|
|
7140
7215
|
const passThroughEncryption = passThrough === true;
|
|
7141
|
-
|
|
7142
|
-
|
|
7216
|
+
let password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
|
|
7217
|
+
let rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
|
|
7143
7218
|
checkPasswordOption(password, rawPassword);
|
|
7219
|
+
password = password && password.length ? password : UNDEFINED_VALUE;
|
|
7220
|
+
rawPassword = rawPassword && rawPassword.length ? rawPassword : UNDEFINED_VALUE;
|
|
7144
7221
|
const encryptionStrength = getNumberOptionValue(zipWriter, options, OPTION_ENCRYPTION_STRENGTH, 3);
|
|
7145
7222
|
const zipCrypto = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIPCRYPTO);
|
|
7146
7223
|
const extendedTimestamp = getOptionValue(zipWriter, options, OPTION_EXTENDED_TIMESTAMP, true);
|
|
@@ -7757,6 +7834,7 @@
|
|
|
7757
7834
|
const result = await runWorker({ readable, writable }, workerOptions);
|
|
7758
7835
|
compressedSize = result.outputSize;
|
|
7759
7836
|
writer.size += compressedSize;
|
|
7837
|
+
throwIfAborted(signal);
|
|
7760
7838
|
if (!passThroughCompression) {
|
|
7761
7839
|
uncompressedSize = result.inputSize;
|
|
7762
7840
|
if (!encrypted || zipCrypto) {
|
|
@@ -8936,7 +9014,7 @@
|
|
|
8936
9014
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
8937
9015
|
*/
|
|
8938
9016
|
|
|
8939
|
-
const VERSION = "2.
|
|
9017
|
+
const VERSION = "2.17.0";
|
|
8940
9018
|
|
|
8941
9019
|
/*
|
|
8942
9020
|
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
|
@@ -9429,7 +9507,12 @@
|
|
|
9429
9507
|
const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
|
|
9430
9508
|
const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
|
|
9431
9509
|
const ERR_UNSUPPORTED_PASS_THROUGH_VALUE = "The 'compressed' passThrough option is only supported by Entry#getData() and ZipWriter#add()";
|
|
9510
|
+
const ERR_INVALID_PASSWORDS = "Invalid passwords option (must be an array of strings)";
|
|
9511
|
+
const ERR_INVALID_REQUEST_PASSWORD = "Invalid requestPassword option (must be a function returning a string or undefined)";
|
|
9432
9512
|
const ERR_ABORT_EXPORT = "zipjs-abort-export";
|
|
9513
|
+
const ABORT_ERROR_NAME = "AbortError";
|
|
9514
|
+
const EMPTY_RAW_PASSWORD = new Uint8Array(0);
|
|
9515
|
+
const FALSE_ACCEPT_ERRORS = new Set([ERR_INVALID_CRC32, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_COMPRESSED_DATA]);
|
|
9433
9516
|
|
|
9434
9517
|
class ZipEntry {
|
|
9435
9518
|
|
|
@@ -9802,8 +9885,10 @@
|
|
|
9802
9885
|
zipReader = new ZipReader(reader, options);
|
|
9803
9886
|
}
|
|
9804
9887
|
checkPassThroughValue(options.passThrough);
|
|
9888
|
+
checkPasswordCandidatesOptions(options);
|
|
9805
9889
|
const duplicates = checkDuplicatesOption(options.duplicates);
|
|
9806
9890
|
const importedEntries = [];
|
|
9891
|
+
const passwordState = { known: [] };
|
|
9807
9892
|
const entries = await zipReader.getEntries(options);
|
|
9808
9893
|
for (const entry of entries) {
|
|
9809
9894
|
let parent = this;
|
|
@@ -9848,7 +9933,7 @@
|
|
|
9848
9933
|
}
|
|
9849
9934
|
importedEntries.push(addChild(parent, name, {
|
|
9850
9935
|
data: entry,
|
|
9851
|
-
Reader: getZipBlobReader(Object.assign({}, options)),
|
|
9936
|
+
Reader: getZipBlobReader(Object.assign({}, options), passwordState),
|
|
9852
9937
|
uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
|
|
9853
9938
|
passThrough: options.passThrough
|
|
9854
9939
|
}));
|
|
@@ -10177,7 +10262,7 @@
|
|
|
10177
10262
|
};
|
|
10178
10263
|
}
|
|
10179
10264
|
|
|
10180
|
-
function getZipBlobReader(options) {
|
|
10265
|
+
function getZipBlobReader(options, passwordState) {
|
|
10181
10266
|
return class extends Reader {
|
|
10182
10267
|
|
|
10183
10268
|
constructor(entry, options = {}) {
|
|
@@ -10190,12 +10275,12 @@
|
|
|
10190
10275
|
const zipBlobReader = this;
|
|
10191
10276
|
const readerOptions = Object.assign({}, options, zipBlobReader.options);
|
|
10192
10277
|
const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
|
|
10193
|
-
const data = await zipBlobReader.entry
|
|
10278
|
+
const data = await readEntryData(zipBlobReader.entry, Object.assign(readerOptions, {
|
|
10194
10279
|
checkPasswordOnly: false,
|
|
10195
10280
|
checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
|
|
10196
10281
|
checkOverlappingEntryOnly: false,
|
|
10197
10282
|
preventClose: false
|
|
10198
|
-
}));
|
|
10283
|
+
}), passwordState);
|
|
10199
10284
|
zipBlobReader.data = data;
|
|
10200
10285
|
zipBlobReader.blobReader = new BlobReader(data);
|
|
10201
10286
|
zipBlobReader.size = data.size;
|
|
@@ -10257,10 +10342,9 @@
|
|
|
10257
10342
|
await initStream(reader);
|
|
10258
10343
|
} catch (error) {
|
|
10259
10344
|
try {
|
|
10345
|
+
error.entry = child;
|
|
10260
10346
|
error.entryId = child.id;
|
|
10261
|
-
error.
|
|
10262
|
-
entry: child
|
|
10263
|
-
};
|
|
10347
|
+
error.entryName = child.getRelativeName(entry);
|
|
10264
10348
|
} catch {
|
|
10265
10349
|
// ignored
|
|
10266
10350
|
}
|
|
@@ -10352,10 +10436,145 @@
|
|
|
10352
10436
|
}
|
|
10353
10437
|
if (readerOptions) {
|
|
10354
10438
|
checkPassThroughValue(readerOptions.passThrough);
|
|
10439
|
+
checkPasswordCandidatesOptions(readerOptions);
|
|
10355
10440
|
}
|
|
10356
10441
|
return readerOptions;
|
|
10357
10442
|
}
|
|
10358
10443
|
|
|
10444
|
+
function checkPasswordCandidatesOptions(options) {
|
|
10445
|
+
const { passwords, requestPassword } = options;
|
|
10446
|
+
if (passwords && (!Array.isArray(passwords) || passwords.some(password => typeof password != STRING_TYPE))) {
|
|
10447
|
+
throw new Error(ERR_INVALID_PASSWORDS);
|
|
10448
|
+
}
|
|
10449
|
+
if (requestPassword && typeof requestPassword != FUNCTION_TYPE) {
|
|
10450
|
+
throw new Error(ERR_INVALID_REQUEST_PASSWORD);
|
|
10451
|
+
}
|
|
10452
|
+
}
|
|
10453
|
+
|
|
10454
|
+
async function readEntryData(entry, options, passwordState) {
|
|
10455
|
+
checkPasswordCandidatesOptions(options);
|
|
10456
|
+
const { passwords, requestPassword, signal } = options;
|
|
10457
|
+
options = Object.assign({}, options);
|
|
10458
|
+
delete options.passwords;
|
|
10459
|
+
delete options.requestPassword;
|
|
10460
|
+
if (!entry.encrypted || options.passThrough || (!passwords && !requestPassword)) {
|
|
10461
|
+
return entry.getData(new BlobWriter(), options);
|
|
10462
|
+
}
|
|
10463
|
+
const tried = new Set();
|
|
10464
|
+
let error;
|
|
10465
|
+
while (true) {
|
|
10466
|
+
for (const candidate of getPasswordCandidates(options, passwordState, passwords)) {
|
|
10467
|
+
if (!tried.has(candidate.key)) {
|
|
10468
|
+
const result = await tryPasswordCandidate(candidate);
|
|
10469
|
+
if (result.done) {
|
|
10470
|
+
return result.data;
|
|
10471
|
+
}
|
|
10472
|
+
error = result.error;
|
|
10473
|
+
}
|
|
10474
|
+
}
|
|
10475
|
+
if (!requestPassword) {
|
|
10476
|
+
break;
|
|
10477
|
+
}
|
|
10478
|
+
if (passwordState.pendingPrompt) {
|
|
10479
|
+
await passwordState.pendingPrompt;
|
|
10480
|
+
continue;
|
|
10481
|
+
}
|
|
10482
|
+
let release;
|
|
10483
|
+
passwordState.pendingPrompt = new Promise(resolve => release = resolve);
|
|
10484
|
+
try {
|
|
10485
|
+
const answer = await requestPassword(entry, error);
|
|
10486
|
+
if (answer === UNDEFINED_VALUE || answer === null) {
|
|
10487
|
+
break;
|
|
10488
|
+
}
|
|
10489
|
+
// deno-lint-ignore valid-typeof
|
|
10490
|
+
if (typeof answer != STRING_TYPE) {
|
|
10491
|
+
throw new Error(ERR_INVALID_REQUEST_PASSWORD);
|
|
10492
|
+
}
|
|
10493
|
+
const result = await tryPasswordCandidate(getPasswordCandidate(answer));
|
|
10494
|
+
if (result.done) {
|
|
10495
|
+
return result.data;
|
|
10496
|
+
}
|
|
10497
|
+
error = result.error;
|
|
10498
|
+
} finally {
|
|
10499
|
+
passwordState.pendingPrompt = UNDEFINED_VALUE;
|
|
10500
|
+
release();
|
|
10501
|
+
}
|
|
10502
|
+
}
|
|
10503
|
+
if (!tried.size) {
|
|
10504
|
+
throw new Error(ERR_ENCRYPTED);
|
|
10505
|
+
}
|
|
10506
|
+
const passwordError = new Error(ERR_INVALID_PASSWORD);
|
|
10507
|
+
passwordError.cause = error;
|
|
10508
|
+
throw passwordError;
|
|
10509
|
+
|
|
10510
|
+
async function tryPasswordCandidate(candidate) {
|
|
10511
|
+
tried.add(candidate.key);
|
|
10512
|
+
const candidateOptions = Object.assign({}, options, candidate.options);
|
|
10513
|
+
if (entry.zipCrypto) {
|
|
10514
|
+
candidateOptions.checkCrc32 = true;
|
|
10515
|
+
try {
|
|
10516
|
+
await entry.getData(null, Object.assign({}, candidateOptions, { checkPasswordOnly: true }));
|
|
10517
|
+
} catch (probeError) {
|
|
10518
|
+
if (isInvalidPasswordError(probeError)) {
|
|
10519
|
+
return { done: false, error: probeError };
|
|
10520
|
+
}
|
|
10521
|
+
throw probeError;
|
|
10522
|
+
}
|
|
10523
|
+
}
|
|
10524
|
+
try {
|
|
10525
|
+
const data = await entry.getData(new BlobWriter(), candidateOptions);
|
|
10526
|
+
rememberPassword(passwordState, candidate);
|
|
10527
|
+
return { done: true, data };
|
|
10528
|
+
} catch (readError) {
|
|
10529
|
+
if (isAbortError(readError, signal) || !isWrongPasswordError(readError, entry)) {
|
|
10530
|
+
throw readError;
|
|
10531
|
+
}
|
|
10532
|
+
return { done: false, error: readError };
|
|
10533
|
+
}
|
|
10534
|
+
}
|
|
10535
|
+
}
|
|
10536
|
+
|
|
10537
|
+
function isInvalidPasswordError(error) {
|
|
10538
|
+
return isErrorObject(error) && error.message == ERR_INVALID_PASSWORD;
|
|
10539
|
+
}
|
|
10540
|
+
|
|
10541
|
+
function isWrongPasswordError(error, entry) {
|
|
10542
|
+
return isInvalidPasswordError(error) || (entry.zipCrypto && isErrorObject(error) && FALSE_ACCEPT_ERRORS.has(error.message));
|
|
10543
|
+
}
|
|
10544
|
+
|
|
10545
|
+
function isAbortError(error, signal) {
|
|
10546
|
+
return Boolean(signal && signal.aborted) || (isErrorObject(error) && error.name == ABORT_ERROR_NAME);
|
|
10547
|
+
}
|
|
10548
|
+
|
|
10549
|
+
function getPasswordCandidates(options, passwordState, passwords) {
|
|
10550
|
+
const candidates = [];
|
|
10551
|
+
const { password, rawPassword } = options;
|
|
10552
|
+
if (rawPassword && rawPassword.length) {
|
|
10553
|
+
candidates.push({ key: rawPassword, options: { password: "", rawPassword } });
|
|
10554
|
+
}
|
|
10555
|
+
if (password) {
|
|
10556
|
+
candidates.push(getPasswordCandidate(password));
|
|
10557
|
+
}
|
|
10558
|
+
candidates.push(...passwordState.known);
|
|
10559
|
+
if (passwords) {
|
|
10560
|
+
candidates.push(...passwords.filter(password => password).map(getPasswordCandidate));
|
|
10561
|
+
}
|
|
10562
|
+
return candidates;
|
|
10563
|
+
}
|
|
10564
|
+
|
|
10565
|
+
function getPasswordCandidate(password) {
|
|
10566
|
+
return { key: password, options: { password, rawPassword: EMPTY_RAW_PASSWORD } };
|
|
10567
|
+
}
|
|
10568
|
+
|
|
10569
|
+
function rememberPassword(passwordState, candidate) {
|
|
10570
|
+
const { known } = passwordState;
|
|
10571
|
+
const index = known.findIndex(knownCandidate => knownCandidate.key === candidate.key);
|
|
10572
|
+
if (index != -1) {
|
|
10573
|
+
known.splice(index, 1);
|
|
10574
|
+
}
|
|
10575
|
+
known.unshift(candidate);
|
|
10576
|
+
}
|
|
10577
|
+
|
|
10359
10578
|
function checkPassThroughValue(passThrough) {
|
|
10360
10579
|
if (checkPassThroughOption(passThrough) === PASS_THROUGH_COMPRESSED) {
|
|
10361
10580
|
throw new Error(ERR_UNSUPPORTED_PASS_THROUGH_VALUE);
|
|
@@ -10493,6 +10712,7 @@
|
|
|
10493
10712
|
async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
|
|
10494
10713
|
const { onstart, onprogress, onend } = options;
|
|
10495
10714
|
checkPassThroughValue(options.passThrough);
|
|
10715
|
+
checkPasswordCandidatesOptions(options);
|
|
10496
10716
|
const readerOptions = checkReaderOptions(options.readerOptions);
|
|
10497
10717
|
const abortController = new AbortController();
|
|
10498
10718
|
const { signal } = abortController;
|
|
@@ -10751,6 +10971,7 @@
|
|
|
10751
10971
|
exports.ERR_ANCESTOR_ENTRY = ERR_ANCESTOR_ENTRY;
|
|
10752
10972
|
exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
|
|
10753
10973
|
exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
|
|
10974
|
+
exports.ERR_CODEC_OUT_OF_MEMORY = ERR_CODEC_OUT_OF_MEMORY;
|
|
10754
10975
|
exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
|
|
10755
10976
|
exports.ERR_DUPLICATE_IMPORTED_ENTRY = ERR_DUPLICATE_IMPORTED_ENTRY;
|
|
10756
10977
|
exports.ERR_ENCRYPTED = ERR_ENCRYPTED;
|
|
@@ -10791,11 +11012,13 @@
|
|
|
10791
11012
|
exports.ERR_INVALID_MSDOS_ATTRIBUTES = ERR_INVALID_MSDOS_ATTRIBUTES;
|
|
10792
11013
|
exports.ERR_INVALID_MSDOS_DATA = ERR_INVALID_MSDOS_DATA;
|
|
10793
11014
|
exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
|
|
11015
|
+
exports.ERR_INVALID_PASSWORDS = ERR_INVALID_PASSWORDS;
|
|
10794
11016
|
exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
|
|
10795
11017
|
exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
|
|
10796
11018
|
exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
|
|
10797
11019
|
exports.ERR_INVALID_READER = ERR_INVALID_READER;
|
|
10798
11020
|
exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
|
|
11021
|
+
exports.ERR_INVALID_REQUEST_PASSWORD = ERR_INVALID_REQUEST_PASSWORD;
|
|
10799
11022
|
exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
|
|
10800
11023
|
exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
|
|
10801
11024
|
exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
|