@zip.js/zip.js 2.8.52 → 2.8.53
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 +154 -52
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +154 -51
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +157 -52
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +143 -47
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +157 -52
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +157 -51
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +157 -51
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +154 -51
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +154 -51
- package/dist/zip-native.min.js +1 -1
- package/dist/zip.js +154 -51
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -1
- package/index-native.cjs +157 -51
- package/index-native.min.js +1 -1
- package/index.cjs +157 -51
- package/index.d.cts +278 -40
- package/index.d.ts +278 -40
- package/index.min.js +1 -1
- package/lib/core/codec-worker-web.js +13 -4
- package/lib/core/constants.js +5 -0
- package/lib/core/io.js +11 -2
- package/lib/core/options.js +2 -0
- package/lib/core/zip-entry.js +8 -0
- package/lib/core/zip-reader.js +91 -34
- package/lib/core/zip-writer.js +36 -12
- package/lib/zip-core-writer.js +1 -0
- package/package.json +5 -3
|
@@ -83,6 +83,7 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
83
83
|
worker,
|
|
84
84
|
workerAlive: false,
|
|
85
85
|
terminated: false,
|
|
86
|
+
startupError: null,
|
|
86
87
|
interface: {
|
|
87
88
|
run: async () => {
|
|
88
89
|
try {
|
|
@@ -110,6 +111,13 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
async function runWebWorker(workerData, config) {
|
|
114
|
+
if (!workerData.worker) {
|
|
115
|
+
const { startupError } = workerData;
|
|
116
|
+
workerData.startupError = null;
|
|
117
|
+
const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
|
|
118
|
+
error.workerStartupFailed = true;
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
113
121
|
let resolveResult, rejectResult;
|
|
114
122
|
const result = new Promise((resolve, reject) => {
|
|
115
123
|
resolveResult = resolve;
|
|
@@ -323,11 +331,12 @@ function onWorkerError(event, workerData) {
|
|
|
323
331
|
if (!workerAlive) {
|
|
324
332
|
workerData.worker = null;
|
|
325
333
|
}
|
|
334
|
+
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
335
|
+
if (!workerAlive) {
|
|
336
|
+
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
337
|
+
workerData.startupError = error;
|
|
338
|
+
}
|
|
326
339
|
if (rejectResult) {
|
|
327
|
-
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
328
|
-
if (!workerAlive) {
|
|
329
|
-
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
330
|
-
}
|
|
331
340
|
rejectResult(error);
|
|
332
341
|
if (writer) {
|
|
333
342
|
writer.releaseLock();
|
package/lib/core/constants.js
CHANGED
|
@@ -93,6 +93,9 @@ const VERSION_DEFLATE = 0x14;
|
|
|
93
93
|
const VERSION_ZIP64 = 0x2D;
|
|
94
94
|
const VERSION_AES = 0x33;
|
|
95
95
|
|
|
96
|
+
const VERSION_MADE_BY_MSDOS = 0x0014;
|
|
97
|
+
const VERSION_MADE_BY_UNIX = 0x0300;
|
|
98
|
+
|
|
96
99
|
const DIRECTORY_SIGNATURE = "/";
|
|
97
100
|
|
|
98
101
|
const HEADER_SIZE = 30;
|
|
@@ -176,6 +179,8 @@ export {
|
|
|
176
179
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
177
180
|
FILE_ATTR_UNIX_STICKY_MASK,
|
|
178
181
|
VERSION_DEFLATE,
|
|
182
|
+
VERSION_MADE_BY_MSDOS,
|
|
183
|
+
VERSION_MADE_BY_UNIX,
|
|
179
184
|
VERSION_ZIP64,
|
|
180
185
|
VERSION_AES,
|
|
181
186
|
HEADER_SIZE,
|
package/lib/core/io.js
CHANGED
|
@@ -791,9 +791,8 @@ class SplitDataReader extends Reader {
|
|
|
791
791
|
|
|
792
792
|
async init() {
|
|
793
793
|
const reader = this;
|
|
794
|
-
const { readers } = reader;
|
|
795
794
|
reader.lastDiskNumber = 0;
|
|
796
|
-
await Promise.all(readers.map(
|
|
795
|
+
const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
|
|
797
796
|
reader.diskOffsets = readers.map(diskReader => {
|
|
798
797
|
const diskOffset = reader.size;
|
|
799
798
|
reader.size += diskReader.size;
|
|
@@ -988,6 +987,16 @@ async function initStream(stream, initSize) {
|
|
|
988
987
|
}
|
|
989
988
|
}
|
|
990
989
|
|
|
990
|
+
async function initDiskReader(diskReader) {
|
|
991
|
+
diskReader = new GenericReader(diskReader);
|
|
992
|
+
await initStream(diskReader);
|
|
993
|
+
if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
|
|
994
|
+
diskReader = new BlobReader(await streamToBlob(diskReader.readable));
|
|
995
|
+
await initStream(diskReader);
|
|
996
|
+
}
|
|
997
|
+
return diskReader;
|
|
998
|
+
}
|
|
999
|
+
|
|
991
1000
|
function readUint8Array(reader, offset, size) {
|
|
992
1001
|
return reader.readUint8Array(offset, size);
|
|
993
1002
|
}
|
package/lib/core/options.js
CHANGED
|
@@ -39,6 +39,7 @@ const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
|
|
|
39
39
|
const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
|
|
40
40
|
const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
|
|
41
41
|
const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
|
|
42
|
+
const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
|
|
42
43
|
const OPTION_CHECK_SIGNATURE = "checkSignature";
|
|
43
44
|
const OPTION_CHECK_CRC32 = "checkCrc32";
|
|
44
45
|
const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
|
|
@@ -88,6 +89,7 @@ export {
|
|
|
88
89
|
OPTION_CHECK_OVERLAPPING_ENTRY_ONLY,
|
|
89
90
|
OPTION_CHECK_OVERLAPPING_ENTRY,
|
|
90
91
|
OPTION_CHECK_AMBIGUITY,
|
|
92
|
+
OPTION_CHECK_LOCAL_DIRECTORY,
|
|
91
93
|
OPTION_CHECK_SIGNATURE,
|
|
92
94
|
OPTION_CHECK_CRC32,
|
|
93
95
|
OPTION_CHECK_AUTHENTICATION_CODE,
|
package/lib/core/zip-entry.js
CHANGED
|
@@ -70,6 +70,10 @@ const PROPERTY_NAME_SETUID = "setuid";
|
|
|
70
70
|
const PROPERTY_NAME_SETGID = "setgid";
|
|
71
71
|
const PROPERTY_NAME_STICKY = "sticky";
|
|
72
72
|
const PROPERTY_NAME_BITFLAG = "bitFlag";
|
|
73
|
+
const PROPERTY_NAME_RAW_BITFLAG = "rawBitFlag";
|
|
74
|
+
const PROPERTY_NAME_FILENAME_LENGTH = "filenameLength";
|
|
75
|
+
const PROPERTY_NAME_EXTRA_FIELD_LENGTH = "extraFieldLength";
|
|
76
|
+
const PROPERTY_NAME_UNIX_EXTERNAL_UPPER = "unixExternalUpper";
|
|
73
77
|
const PROPERTY_NAME_FILENAME_UTF8 = "filenameUTF8";
|
|
74
78
|
const PROPERTY_NAME_COMMENT_UTF8 = "commentUTF8";
|
|
75
79
|
const PROPERTY_NAME_RAW_EXTRA_FIELD = "rawExtraField";
|
|
@@ -122,10 +126,14 @@ const PROPERTY_NAMES = [
|
|
|
122
126
|
PROPERTY_NAME_UID,
|
|
123
127
|
PROPERTY_NAME_GID,
|
|
124
128
|
PROPERTY_NAME_UNIX_MODE,
|
|
129
|
+
PROPERTY_NAME_UNIX_EXTERNAL_UPPER,
|
|
125
130
|
PROPERTY_NAME_SETUID,
|
|
126
131
|
PROPERTY_NAME_SETGID,
|
|
127
132
|
PROPERTY_NAME_STICKY,
|
|
128
133
|
PROPERTY_NAME_BITFLAG,
|
|
134
|
+
PROPERTY_NAME_RAW_BITFLAG,
|
|
135
|
+
PROPERTY_NAME_FILENAME_LENGTH,
|
|
136
|
+
PROPERTY_NAME_EXTRA_FIELD_LENGTH,
|
|
129
137
|
PROPERTY_NAME_FILENAME_UTF8,
|
|
130
138
|
PROPERTY_NAME_COMMENT_UTF8,
|
|
131
139
|
PROPERTY_NAME_RAW_EXTRA_FIELD,
|
package/lib/core/zip-reader.js
CHANGED
|
@@ -150,6 +150,7 @@ import {
|
|
|
150
150
|
OPTION_CHECK_OVERLAPPING_ENTRY_ONLY,
|
|
151
151
|
OPTION_CHECK_OVERLAPPING_ENTRY,
|
|
152
152
|
OPTION_CHECK_AMBIGUITY,
|
|
153
|
+
OPTION_CHECK_LOCAL_DIRECTORY,
|
|
153
154
|
OPTION_CHECK_SIGNATURE,
|
|
154
155
|
OPTION_CHECK_CRC32,
|
|
155
156
|
OPTION_CHECK_AUTHENTICATION_CODE,
|
|
@@ -236,7 +237,7 @@ class ZipReader {
|
|
|
236
237
|
if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
|
|
237
238
|
throw new Error(ERR_BAD_FORMAT);
|
|
238
239
|
}
|
|
239
|
-
const strictness = getStrictness(
|
|
240
|
+
const strictness = getStrictness(options, zipReader.options);
|
|
240
241
|
const checkAmbiguity = strictness == STRICTNESS_STRICT;
|
|
241
242
|
const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
|
|
242
243
|
const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
|
|
@@ -458,6 +459,7 @@ class ZipReader {
|
|
|
458
459
|
index: indexFile,
|
|
459
460
|
versionMadeBy,
|
|
460
461
|
msDosCompatible,
|
|
462
|
+
zip64: false,
|
|
461
463
|
compressedSize: 0,
|
|
462
464
|
uncompressedSize: 0,
|
|
463
465
|
commentLength,
|
|
@@ -697,9 +699,12 @@ class ZipEntry {
|
|
|
697
699
|
extraFieldLength,
|
|
698
700
|
filenameLength
|
|
699
701
|
} = localDirectory;
|
|
700
|
-
const
|
|
702
|
+
const checkLocalDirectoryOption = getOptionValue(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
|
|
703
|
+
const entryStrictness = getStrictness(options, zipEntry.options);
|
|
704
|
+
const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
|
|
705
|
+
const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
|
|
701
706
|
let rawLocalFilename = EMPTY_UINT8_ARRAY;
|
|
702
|
-
if (
|
|
707
|
+
if (checkLocalFilename && (filenameLength || extraFieldLength)) {
|
|
703
708
|
const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
|
|
704
709
|
rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
|
|
705
710
|
localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
|
|
@@ -708,17 +713,26 @@ class ZipEntry {
|
|
|
708
713
|
await readUint8Array(reader, localHeaderOffset + HEADER_SIZE + filenameLength, extraFieldLength) :
|
|
709
714
|
EMPTY_UINT8_ARRAY;
|
|
710
715
|
}
|
|
716
|
+
if (checkLocalFilename) {
|
|
717
|
+
localDirectory.rawFilename = rawLocalFilename;
|
|
718
|
+
}
|
|
711
719
|
readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
|
|
712
|
-
if (
|
|
713
|
-
|
|
720
|
+
if (checkLocalDirectory) {
|
|
721
|
+
validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
|
|
714
722
|
}
|
|
715
|
-
const { lastAccessDate, creationDate } = localDirectory;
|
|
723
|
+
const { lastAccessDate, creationDate, uid, gid } = localDirectory;
|
|
716
724
|
if (lastAccessDate) {
|
|
717
725
|
fileEntry.lastAccessDate = lastAccessDate;
|
|
718
726
|
}
|
|
719
727
|
if (creationDate) {
|
|
720
728
|
fileEntry.creationDate = creationDate;
|
|
721
729
|
}
|
|
730
|
+
if (uid !== UNDEFINED_VALUE && fileEntry.uid === UNDEFINED_VALUE) {
|
|
731
|
+
fileEntry.uid = uid;
|
|
732
|
+
}
|
|
733
|
+
if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
|
|
734
|
+
fileEntry.gid = gid;
|
|
735
|
+
}
|
|
722
736
|
const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
|
|
723
737
|
const zipCrypto = encrypted && !extraFieldAES;
|
|
724
738
|
if (!passThrough) {
|
|
@@ -954,10 +968,12 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
|
|
|
954
968
|
directory.extraFieldNTFS = extraFieldNTFS;
|
|
955
969
|
}
|
|
956
970
|
const extraFieldUnix = extraField.get(EXTRAFIELD_TYPE_UNIX);
|
|
971
|
+
let unixIdsRead;
|
|
957
972
|
if (extraFieldUnix) {
|
|
958
|
-
readExtraFieldUnix(extraFieldUnix, directory, false);
|
|
973
|
+
unixIdsRead = readExtraFieldUnix(extraFieldUnix, directory, false);
|
|
959
974
|
directory.extraFieldUnix = extraFieldUnix;
|
|
960
|
-
}
|
|
975
|
+
}
|
|
976
|
+
if (!unixIdsRead) {
|
|
961
977
|
const extraFieldInfoZip = extraField.get(EXTRAFIELD_TYPE_INFOZIP);
|
|
962
978
|
if (extraFieldInfoZip) {
|
|
963
979
|
readExtraFieldUnix(extraFieldInfoZip, directory, true);
|
|
@@ -1060,7 +1076,7 @@ function readExtraFieldNTFS(extraFieldNTFS, directory) {
|
|
|
1060
1076
|
const creationDate = getDateNTFS(rawCreationDate);
|
|
1061
1077
|
const extraFieldData = { lastModDate, lastAccessDate, creationDate };
|
|
1062
1078
|
Object.assign(extraFieldNTFS, extraFieldData);
|
|
1063
|
-
Object.assign(directory, extraFieldData);
|
|
1079
|
+
Object.assign(directory, extraFieldData, { rawLastAccessDate, rawCreationDate });
|
|
1064
1080
|
}
|
|
1065
1081
|
}
|
|
1066
1082
|
|
|
@@ -1104,6 +1120,7 @@ function readExtraFieldUnix(extraField, directory, isInfoZip) {
|
|
|
1104
1120
|
if (gid !== UNDEFINED_VALUE) {
|
|
1105
1121
|
directory.gid = gid;
|
|
1106
1122
|
}
|
|
1123
|
+
return uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE;
|
|
1107
1124
|
} catch {
|
|
1108
1125
|
// ignored
|
|
1109
1126
|
}
|
|
@@ -1176,26 +1193,25 @@ async function detectOverlappingEntry({
|
|
|
1176
1193
|
}
|
|
1177
1194
|
if (dataDescriptorLength) {
|
|
1178
1195
|
const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH);
|
|
1179
|
-
const
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
if (extraFieldZip64) {
|
|
1186
|
-
readCompressedSize = getBigUint64(getDataView(dataDescriptorArray), 8);
|
|
1187
|
-
readUncompressedSize = getBigUint64(getDataView(dataDescriptorArray), 16);
|
|
1188
|
-
} else {
|
|
1189
|
-
readCompressedSize = getUint32(getDataView(dataDescriptorArray), 8);
|
|
1190
|
-
readUncompressedSize = getUint32(getDataView(dataDescriptorArray), 12);
|
|
1191
|
-
}
|
|
1192
|
-
const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || readCrc32 == crc32;
|
|
1196
|
+
const dataDescriptorView = getDataView(dataDescriptorArray);
|
|
1197
|
+
let signature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
|
|
1198
|
+
getUint32(dataDescriptorView, 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
|
|
1199
|
+
if (signature) {
|
|
1200
|
+
const signedDataDescriptor = readDataDescriptor(dataDescriptorView, DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, extraFieldZip64);
|
|
1201
|
+
const matchCrc32 = (fileEntry.encrypted && !fileEntry.zipCrypto) || signedDataDescriptor.crc32 == crc32;
|
|
1193
1202
|
if (matchCrc32 &&
|
|
1194
|
-
|
|
1195
|
-
|
|
1203
|
+
signedDataDescriptor.compressedSize == compressedSize &&
|
|
1204
|
+
signedDataDescriptor.uncompressedSize == uncompressedSize) {
|
|
1196
1205
|
dataDescriptorLength += DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH;
|
|
1206
|
+
} else {
|
|
1207
|
+
signature = false;
|
|
1197
1208
|
}
|
|
1198
1209
|
}
|
|
1210
|
+
if (dataDescriptorArray.length >= dataDescriptorLength) {
|
|
1211
|
+
const localDataDescriptor = readDataDescriptor(dataDescriptorView, signature ? DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH : 0, extraFieldZip64);
|
|
1212
|
+
localDataDescriptor.signature = signature;
|
|
1213
|
+
fileEntry.localDirectory.dataDescriptor = localDataDescriptor;
|
|
1214
|
+
}
|
|
1199
1215
|
}
|
|
1200
1216
|
const range = {
|
|
1201
1217
|
start: offset,
|
|
@@ -1212,6 +1228,20 @@ async function detectOverlappingEntry({
|
|
|
1212
1228
|
readRanges.set(index, range);
|
|
1213
1229
|
}
|
|
1214
1230
|
|
|
1231
|
+
function readDataDescriptor(dataDescriptorView, offset, extraFieldZip64) {
|
|
1232
|
+
const crc32 = getUint32(dataDescriptorView, offset);
|
|
1233
|
+
let compressedSize;
|
|
1234
|
+
let uncompressedSize;
|
|
1235
|
+
if (extraFieldZip64) {
|
|
1236
|
+
compressedSize = getBigUint64(dataDescriptorView, offset + 4);
|
|
1237
|
+
uncompressedSize = getBigUint64(dataDescriptorView, offset + 12);
|
|
1238
|
+
} else {
|
|
1239
|
+
compressedSize = getUint32(dataDescriptorView, offset + 4);
|
|
1240
|
+
uncompressedSize = getUint32(dataDescriptorView, offset + 8);
|
|
1241
|
+
}
|
|
1242
|
+
return { crc32, compressedSize, uncompressedSize };
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1215
1245
|
function getDiskOffset(reader, diskNumber) {
|
|
1216
1246
|
return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
|
|
1217
1247
|
}
|
|
@@ -1220,14 +1250,40 @@ function isStrictnessValue(value) {
|
|
|
1220
1250
|
return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
|
|
1221
1251
|
}
|
|
1222
1252
|
|
|
1223
|
-
function getStrictness(
|
|
1224
|
-
|
|
1225
|
-
|
|
1253
|
+
function getStrictness(options, inheritedOptions) {
|
|
1254
|
+
return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
function resolveStrictness(options, inheritedStrictness) {
|
|
1258
|
+
const strictness = options[OPTION_STRICTNESS];
|
|
1259
|
+
if (strictness !== UNDEFINED_VALUE) {
|
|
1260
|
+
if (!isStrictnessValue(strictness)) {
|
|
1261
|
+
throw new Error(ERR_INVALID_STRICTNESS);
|
|
1262
|
+
}
|
|
1263
|
+
return strictness;
|
|
1264
|
+
}
|
|
1265
|
+
const checkAmbiguity = options[OPTION_CHECK_AMBIGUITY];
|
|
1266
|
+
if (checkAmbiguity === UNDEFINED_VALUE) {
|
|
1267
|
+
return inheritedStrictness;
|
|
1268
|
+
}
|
|
1269
|
+
if (checkAmbiguity) {
|
|
1270
|
+
return STRICTNESS_STRICT;
|
|
1271
|
+
}
|
|
1272
|
+
return inheritedStrictness == STRICTNESS_TOLERANT ? STRICTNESS_TOLERANT : STRICTNESS_BALANCED;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
function getCheckLocalDirectory(checkLocalDirectory, strictness) {
|
|
1276
|
+
if (checkLocalDirectory === UNDEFINED_VALUE) {
|
|
1277
|
+
return strictness != STRICTNESS_TOLERANT;
|
|
1226
1278
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1279
|
+
return Boolean(checkLocalDirectory);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function getCheckLocalFilename(checkLocalFilename, strictness) {
|
|
1283
|
+
if (checkLocalFilename === UNDEFINED_VALUE) {
|
|
1284
|
+
return strictness == STRICTNESS_STRICT;
|
|
1229
1285
|
}
|
|
1230
|
-
return
|
|
1286
|
+
return Boolean(checkLocalFilename);
|
|
1231
1287
|
}
|
|
1232
1288
|
|
|
1233
1289
|
function getFilenameValidation(filenameValidation, strictness) {
|
|
@@ -1375,10 +1431,11 @@ async function readSignature(reader, view, anchoredOffset, signatureOffset, size
|
|
|
1375
1431
|
return UNDEFINED_VALUE;
|
|
1376
1432
|
}
|
|
1377
1433
|
|
|
1378
|
-
function
|
|
1434
|
+
function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
|
|
1379
1435
|
const { rawFilename } = zipEntry;
|
|
1380
|
-
if (
|
|
1381
|
-
rawLocalFilename.
|
|
1436
|
+
if (checkLocalFilename &&
|
|
1437
|
+
(rawLocalFilename.length != rawFilename.length ||
|
|
1438
|
+
rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
|
|
1382
1439
|
throwAmbiguousArchive("mismatched local file header (filename)");
|
|
1383
1440
|
}
|
|
1384
1441
|
if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
|
package/lib/core/zip-writer.js
CHANGED
|
@@ -122,12 +122,15 @@ import {
|
|
|
122
122
|
FILE_ATTR_UNIX_TYPE_DIR,
|
|
123
123
|
FILE_ATTR_UNIX_TYPE_FILE,
|
|
124
124
|
FILE_ATTR_UNIX_TYPE_MASK,
|
|
125
|
+
FILE_ATTR_UNIX_TYPE_SYMLINK,
|
|
125
126
|
FILE_ATTR_UNIX_EXECUTABLE_MASK,
|
|
126
127
|
FILE_ATTR_UNIX_DEFAULT_MASK,
|
|
127
128
|
FILE_ATTR_UNIX_SETUID_MASK,
|
|
128
129
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
129
130
|
FILE_ATTR_UNIX_STICKY_MASK,
|
|
130
131
|
VERSION_DEFLATE,
|
|
132
|
+
VERSION_MADE_BY_MSDOS,
|
|
133
|
+
VERSION_MADE_BY_UNIX,
|
|
131
134
|
VERSION_ZIP64,
|
|
132
135
|
VERSION_AES,
|
|
133
136
|
DIRECTORY_SIGNATURE,
|
|
@@ -157,11 +160,12 @@ import {
|
|
|
157
160
|
initStream,
|
|
158
161
|
GenericWriter,
|
|
159
162
|
GenericReader,
|
|
163
|
+
BlobReader,
|
|
160
164
|
ownsWritable
|
|
161
165
|
} from "./io.js";
|
|
162
166
|
import { encodeText } from "./util/encode-text.js";
|
|
163
167
|
import { getDataView } from "./util/array.js";
|
|
164
|
-
import { toCompatibleReadable } from "./util/compatible-streams.js";
|
|
168
|
+
import { toCompatibleReadable, streamToBlob } from "./util/compatible-streams.js";
|
|
165
169
|
import {
|
|
166
170
|
PROPERTY_NAME_LAST_MODIFICATION_DATE,
|
|
167
171
|
PROPERTY_NAME_LAST_ACCESS_DATE,
|
|
@@ -225,6 +229,7 @@ import {
|
|
|
225
229
|
|
|
226
230
|
const ERR_DUPLICATED_NAME = "File already exists";
|
|
227
231
|
const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
|
|
232
|
+
const ERR_INVALID_COMMENT_TYPE = "Invalid zip file comment (must be a Uint8Array)";
|
|
228
233
|
const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB";
|
|
229
234
|
const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
|
|
230
235
|
const ERR_INVALID_VERSION = "Version exceeds 65535";
|
|
@@ -293,6 +298,10 @@ class ZipWriter {
|
|
|
293
298
|
}
|
|
294
299
|
reader = new GenericReader(reader);
|
|
295
300
|
await initStream(reader);
|
|
301
|
+
if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
|
|
302
|
+
reader = new BlobReader(await streamToBlob(reader.readable));
|
|
303
|
+
await initStream(reader);
|
|
304
|
+
}
|
|
296
305
|
const { ZipReader } = await import("./zip-reader.js");
|
|
297
306
|
const zipReader = new ZipReader(reader.readable);
|
|
298
307
|
const entries = await zipReader.getEntries();
|
|
@@ -441,6 +450,9 @@ class ZipWriter {
|
|
|
441
450
|
const zipWriter = this;
|
|
442
451
|
const { pendingAddFileCalls, writer } = this;
|
|
443
452
|
const { writable } = writer;
|
|
453
|
+
if (!(comment instanceof Uint8Array)) {
|
|
454
|
+
throw new Error(ERR_INVALID_COMMENT_TYPE);
|
|
455
|
+
}
|
|
444
456
|
if (getLength(comment) > MAX_16_BITS) {
|
|
445
457
|
throw new Error(ERR_INVALID_COMMENT);
|
|
446
458
|
}
|
|
@@ -524,6 +536,7 @@ export {
|
|
|
524
536
|
getEntriesSize,
|
|
525
537
|
ERR_DUPLICATED_NAME,
|
|
526
538
|
ERR_INVALID_COMMENT,
|
|
539
|
+
ERR_INVALID_COMMENT_TYPE,
|
|
527
540
|
ERR_INVALID_ENTRY_NAME,
|
|
528
541
|
ERR_INVALID_ENTRY_COMMENT,
|
|
529
542
|
ERR_INVALID_VERSION,
|
|
@@ -569,8 +582,6 @@ async function addFile(zipWriter, name, reader, options) {
|
|
|
569
582
|
const diskOffset = getDiskOffset(zipWriter.writer);
|
|
570
583
|
const diskNumber = getDiskNumber(zipWriter.writer);
|
|
571
584
|
options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
|
|
572
|
-
internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
|
|
573
|
-
externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
|
|
574
585
|
signature: options[PROPERTY_NAME_SIGNATURE],
|
|
575
586
|
crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
|
|
576
587
|
offset: zipWriter.offset - diskOffset,
|
|
@@ -584,14 +595,20 @@ async function addFile(zipWriter, name, reader, options) {
|
|
|
584
595
|
zipWriter.files.delete(name);
|
|
585
596
|
throw error;
|
|
586
597
|
}
|
|
587
|
-
Object.assign(fileEntry, {
|
|
598
|
+
Object.assign(fileEntry, {
|
|
599
|
+
name,
|
|
600
|
+
comment,
|
|
601
|
+
extraField,
|
|
602
|
+
[PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
|
|
603
|
+
[PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
|
|
604
|
+
});
|
|
588
605
|
return new Entry(fileEntry);
|
|
589
606
|
}
|
|
590
607
|
|
|
591
608
|
function resolveAttributes(zipWriter, name, options) {
|
|
592
609
|
name = name.trim();
|
|
593
610
|
let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
|
|
594
|
-
let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ?
|
|
611
|
+
let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
|
|
595
612
|
const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
|
|
596
613
|
const uid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_UID);
|
|
597
614
|
const gid = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_GID);
|
|
@@ -625,7 +642,7 @@ function resolveAttributes(zipWriter, name, options) {
|
|
|
625
642
|
const hasMsDosProvided = msdosAttributesRaw !== UNDEFINED_VALUE || msdosAttributes !== UNDEFINED_VALUE;
|
|
626
643
|
if (hasUnixMetadata) {
|
|
627
644
|
msDosCompatible = false;
|
|
628
|
-
versionMadeBy = (versionMadeBy &
|
|
645
|
+
versionMadeBy = (versionMadeBy & MAX_8_BITS) | VERSION_MADE_BY_UNIX;
|
|
629
646
|
} else if (hasMsDosProvided) {
|
|
630
647
|
msDosCompatible = true;
|
|
631
648
|
versionMadeBy = (versionMadeBy & MAX_8_BITS);
|
|
@@ -665,11 +682,10 @@ function resolveAttributes(zipWriter, name, options) {
|
|
|
665
682
|
externalFileAttributes = FILE_ATTR_UNIX_DEFAULT_MASK << 16;
|
|
666
683
|
}
|
|
667
684
|
}
|
|
668
|
-
let unixExternalUpper;
|
|
669
685
|
if (!msDosCompatible) {
|
|
670
686
|
const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
|
|
671
|
-
|
|
672
|
-
unixMode = unixMode === UNDEFINED_VALUE ?
|
|
687
|
+
const defaultUnixMode = (externalFileAttributes >> 16) & MAX_16_BITS;
|
|
688
|
+
unixMode = unixMode === UNDEFINED_VALUE ? defaultUnixMode : (unixMode & MAX_16_BITS);
|
|
673
689
|
if (setuid) {
|
|
674
690
|
unixMode |= FILE_ATTR_UNIX_SETUID_MASK;
|
|
675
691
|
} else {
|
|
@@ -698,17 +714,20 @@ function resolveAttributes(zipWriter, name, options) {
|
|
|
698
714
|
if (hasMsDosProvided) {
|
|
699
715
|
externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
|
|
700
716
|
}
|
|
717
|
+
const unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
|
|
718
|
+
const symlink = unixMode !== UNDEFINED_VALUE && ((unixMode & FILE_ATTR_UNIX_TYPE_MASK) == FILE_ATTR_UNIX_TYPE_SYMLINK);
|
|
701
719
|
return {
|
|
702
720
|
name,
|
|
703
721
|
resolvedOptions: {
|
|
704
722
|
versionMadeBy,
|
|
705
|
-
msDosCompatible,
|
|
723
|
+
msDosCompatible: Boolean(msDosCompatible),
|
|
706
724
|
externalFileAttributes,
|
|
707
725
|
unixExternalUpper,
|
|
708
726
|
uid,
|
|
709
727
|
gid,
|
|
710
728
|
unixMode,
|
|
711
729
|
unixExtraFieldType,
|
|
730
|
+
symlink,
|
|
712
731
|
setuid,
|
|
713
732
|
setgid,
|
|
714
733
|
sticky,
|
|
@@ -941,6 +960,9 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
|
|
|
941
960
|
if (writerOptions[OPTION_SIGN_CENTRAL_DIRECTORY]) {
|
|
942
961
|
throw new Error(ERR_UNDETERMINED_SIZE);
|
|
943
962
|
}
|
|
963
|
+
if (comment !== UNDEFINED_VALUE && !(comment instanceof Uint8Array)) {
|
|
964
|
+
throw new Error(ERR_INVALID_COMMENT_TYPE);
|
|
965
|
+
}
|
|
944
966
|
const commentLength = getLength(comment);
|
|
945
967
|
if (commentLength > MAX_16_BITS) {
|
|
946
968
|
throw new Error(ERR_INVALID_COMMENT);
|
|
@@ -1222,6 +1244,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
|
|
|
1222
1244
|
uid,
|
|
1223
1245
|
gid,
|
|
1224
1246
|
unixMode,
|
|
1247
|
+
symlink,
|
|
1225
1248
|
setuid,
|
|
1226
1249
|
setgid,
|
|
1227
1250
|
sticky,
|
|
@@ -1258,6 +1281,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
|
|
|
1258
1281
|
uid,
|
|
1259
1282
|
gid,
|
|
1260
1283
|
unixMode,
|
|
1284
|
+
symlink: Boolean(symlink),
|
|
1261
1285
|
setuid,
|
|
1262
1286
|
setgid,
|
|
1263
1287
|
sticky,
|
|
@@ -1338,8 +1362,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
|
|
|
1338
1362
|
rawLastModDate,
|
|
1339
1363
|
creationDate,
|
|
1340
1364
|
lastAccessDate,
|
|
1341
|
-
encrypted,
|
|
1342
|
-
zipCrypto,
|
|
1365
|
+
encrypted: Boolean(encrypted),
|
|
1366
|
+
zipCrypto: Boolean(zipCrypto),
|
|
1343
1367
|
size: metadataSize + compressedSize,
|
|
1344
1368
|
compressionMethod,
|
|
1345
1369
|
version,
|
package/lib/zip-core-writer.js
CHANGED
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "A JavaScript library to zip and unzip files in the browser, Deno and Node.js",
|
|
4
4
|
"author": "Gildas Lormeau",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
|
-
"version": "2.8.
|
|
6
|
+
"version": "2.8.53",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"zip",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"lint": "npx eslint . && deno lint",
|
|
38
|
-
"test": "npm run test-node && npm run test-deno && npm run test-bun && npm run test-node-dist && npm run test-deno-dist && npm run test-bun-dist && npm run test-web-streams-polyfill && npm run test-types",
|
|
38
|
+
"test": "npm run test-node && npm run test-deno && npm run test-bun && npm run test-node-dist && npm run test-deno-dist && npm run test-bun-dist && npm run test-web-streams-polyfill && npm run test-types && npm run test-api-symmetry && npm run test-api-shape",
|
|
39
39
|
"test-browsers": "npm run test-chrome && npm run test-firefox && npm run test-safari",
|
|
40
40
|
"serve-tests": "http-server -p 8888 -c-1 .",
|
|
41
41
|
"test-all": "npm run lint && npm run test && npm run test-browsers",
|
|
@@ -46,11 +46,13 @@
|
|
|
46
46
|
"test-deno": "cd ./tests && deno test --allow-read ./deno-runner.js",
|
|
47
47
|
"test-web-streams-polyfill": "cd ./tests && deno run --allow-read ./web-streams-polyfill-runner.js",
|
|
48
48
|
"test-node": "cd ./tests && node ./node-runner.js",
|
|
49
|
-
"test-bun": "cd ./tests && bun test ./bun-runner.js
|
|
49
|
+
"test-bun": "cd ./tests && bun test ./bun-runner.js",
|
|
50
50
|
"test-deno-dist": "./tests/dist-runner.sh deno",
|
|
51
51
|
"test-node-dist": "./tests/dist-runner.sh node",
|
|
52
52
|
"test-bun-dist": "./tests/dist-runner.sh bun",
|
|
53
53
|
"test-types": "tsc -p ./tests/types/tsconfig.json",
|
|
54
|
+
"test-api-symmetry": "node ./tests/api-symmetry/audit.js",
|
|
55
|
+
"test-api-shape": "node ./tests/api-symmetry/shape.js",
|
|
54
56
|
"test-firefox": "node ./tests/browser-runner.js firefox",
|
|
55
57
|
"test-chrome": "node ./tests/browser-runner.js chrome",
|
|
56
58
|
"test-safari": "node ./tests/browser-runner.js safari"
|