ghc-proxy 0.4.0 → 0.4.2
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.
|
@@ -2376,12 +2376,20 @@ Primary entry point, Node.js specific entry point is index.js
|
|
|
2376
2376
|
const reasonableDetectionSizeInBytes = 4100;
|
|
2377
2377
|
const maximumMpegOffsetTolerance = reasonableDetectionSizeInBytes - 2;
|
|
2378
2378
|
const maximumZipEntrySizeInBytes = 1024 * 1024;
|
|
2379
|
+
const maximumZipEntryCount = 1024;
|
|
2380
|
+
const maximumZipBufferedReadSizeInBytes = 2 ** 31 - 1;
|
|
2379
2381
|
const maximumUntrustedSkipSizeInBytes = 16 * 1024 * 1024;
|
|
2382
|
+
const maximumZipTextEntrySizeInBytes = maximumZipEntrySizeInBytes;
|
|
2380
2383
|
const maximumNestedGzipDetectionSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
2384
|
+
const maximumNestedGzipProbeDepth = 1;
|
|
2381
2385
|
const maximumId3HeaderSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
2382
2386
|
const maximumEbmlDocumentTypeSizeInBytes = 64;
|
|
2383
2387
|
const maximumEbmlElementPayloadSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
2384
2388
|
const maximumEbmlElementCount = 256;
|
|
2389
|
+
const maximumPngChunkCount = 512;
|
|
2390
|
+
const maximumAsfHeaderObjectCount = 512;
|
|
2391
|
+
const maximumTiffTagCount = 512;
|
|
2392
|
+
const maximumDetectionReentryCount = 256;
|
|
2385
2393
|
const maximumPngChunkSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
2386
2394
|
const maximumTiffIfdOffsetInBytes = maximumUntrustedSkipSizeInBytes;
|
|
2387
2395
|
const recoverableZipErrorMessages = new Set([
|
|
@@ -2389,7 +2397,12 @@ const recoverableZipErrorMessages = new Set([
|
|
|
2389
2397
|
"Encrypted ZIP",
|
|
2390
2398
|
"Expected Central-File-Header signature"
|
|
2391
2399
|
]);
|
|
2392
|
-
const recoverableZipErrorMessagePrefixes = [
|
|
2400
|
+
const recoverableZipErrorMessagePrefixes = [
|
|
2401
|
+
"ZIP entry count exceeds ",
|
|
2402
|
+
"Unsupported ZIP compression method:",
|
|
2403
|
+
"ZIP entry compressed data exceeds ",
|
|
2404
|
+
"ZIP entry decompressed data exceeds "
|
|
2405
|
+
];
|
|
2393
2406
|
const recoverableZipErrorCodes = new Set([
|
|
2394
2407
|
"Z_BUF_ERROR",
|
|
2395
2408
|
"Z_DATA_ERROR",
|
|
@@ -2440,10 +2453,83 @@ async function decompressDeflateRawWithLimit(data, { maximumLength = maximumZipE
|
|
|
2440
2453
|
}
|
|
2441
2454
|
return uncompressedData;
|
|
2442
2455
|
}
|
|
2456
|
+
const zipDataDescriptorSignature = 134695760;
|
|
2457
|
+
const zipDataDescriptorLengthInBytes = 16;
|
|
2458
|
+
const zipDataDescriptorOverlapLengthInBytes = zipDataDescriptorLengthInBytes - 1;
|
|
2459
|
+
function findZipDataDescriptorOffset(buffer, bytesConsumed) {
|
|
2460
|
+
if (buffer.length < zipDataDescriptorLengthInBytes) return -1;
|
|
2461
|
+
const lastPossibleDescriptorOffset = buffer.length - zipDataDescriptorLengthInBytes;
|
|
2462
|
+
for (let index = 0; index <= lastPossibleDescriptorOffset; index++) if (UINT32_LE.get(buffer, index) === zipDataDescriptorSignature && UINT32_LE.get(buffer, index + 8) === bytesConsumed + index) return index;
|
|
2463
|
+
return -1;
|
|
2464
|
+
}
|
|
2465
|
+
function mergeByteChunks(chunks, totalLength) {
|
|
2466
|
+
const merged = new Uint8Array(totalLength);
|
|
2467
|
+
let offset = 0;
|
|
2468
|
+
for (const chunk of chunks) {
|
|
2469
|
+
merged.set(chunk, offset);
|
|
2470
|
+
offset += chunk.length;
|
|
2471
|
+
}
|
|
2472
|
+
return merged;
|
|
2473
|
+
}
|
|
2474
|
+
async function readZipDataDescriptorEntryWithLimit(zipHandler, { shouldBuffer, maximumLength = maximumZipEntrySizeInBytes } = {}) {
|
|
2475
|
+
const { syncBuffer } = zipHandler;
|
|
2476
|
+
const { length: syncBufferLength } = syncBuffer;
|
|
2477
|
+
const chunks = [];
|
|
2478
|
+
let bytesConsumed = 0;
|
|
2479
|
+
for (;;) {
|
|
2480
|
+
const length = await zipHandler.tokenizer.peekBuffer(syncBuffer, { mayBeLess: true });
|
|
2481
|
+
const dataDescriptorOffset = findZipDataDescriptorOffset(syncBuffer.subarray(0, length), bytesConsumed);
|
|
2482
|
+
const retainedLength = dataDescriptorOffset >= 0 ? 0 : length === syncBufferLength ? Math.min(zipDataDescriptorOverlapLengthInBytes, length - 1) : 0;
|
|
2483
|
+
const chunkLength = dataDescriptorOffset >= 0 ? dataDescriptorOffset : length - retainedLength;
|
|
2484
|
+
if (chunkLength === 0) break;
|
|
2485
|
+
bytesConsumed += chunkLength;
|
|
2486
|
+
if (bytesConsumed > maximumLength) throw new Error(`ZIP entry compressed data exceeds ${maximumLength} bytes`);
|
|
2487
|
+
if (shouldBuffer) {
|
|
2488
|
+
const data = new Uint8Array(chunkLength);
|
|
2489
|
+
await zipHandler.tokenizer.readBuffer(data);
|
|
2490
|
+
chunks.push(data);
|
|
2491
|
+
} else await zipHandler.tokenizer.ignore(chunkLength);
|
|
2492
|
+
if (dataDescriptorOffset >= 0) break;
|
|
2493
|
+
}
|
|
2494
|
+
if (!shouldBuffer) return;
|
|
2495
|
+
return mergeByteChunks(chunks, bytesConsumed);
|
|
2496
|
+
}
|
|
2497
|
+
async function readZipEntryData(zipHandler, zipHeader, { shouldBuffer } = {}) {
|
|
2498
|
+
if (zipHeader.dataDescriptor && zipHeader.compressedSize === 0) return readZipDataDescriptorEntryWithLimit(zipHandler, { shouldBuffer });
|
|
2499
|
+
if (!shouldBuffer) {
|
|
2500
|
+
await zipHandler.tokenizer.ignore(zipHeader.compressedSize);
|
|
2501
|
+
return;
|
|
2502
|
+
}
|
|
2503
|
+
const maximumLength = getMaximumZipBufferedReadLength(zipHandler.tokenizer);
|
|
2504
|
+
if (!Number.isFinite(zipHeader.compressedSize) || zipHeader.compressedSize < 0 || zipHeader.compressedSize > maximumLength) throw new Error(`ZIP entry compressed data exceeds ${maximumLength} bytes`);
|
|
2505
|
+
const fileData = new Uint8Array(zipHeader.compressedSize);
|
|
2506
|
+
await zipHandler.tokenizer.readBuffer(fileData);
|
|
2507
|
+
return fileData;
|
|
2508
|
+
}
|
|
2443
2509
|
ZipHandler.prototype.inflate = async function(zipHeader, fileData, callback) {
|
|
2444
2510
|
if (zipHeader.compressedMethod === 0) return callback(fileData);
|
|
2445
2511
|
if (zipHeader.compressedMethod !== 8) throw new Error(`Unsupported ZIP compression method: ${zipHeader.compressedMethod}`);
|
|
2446
|
-
return callback(await decompressDeflateRawWithLimit(fileData, { maximumLength:
|
|
2512
|
+
return callback(await decompressDeflateRawWithLimit(fileData, { maximumLength: maximumZipEntrySizeInBytes }));
|
|
2513
|
+
};
|
|
2514
|
+
ZipHandler.prototype.unzip = async function(fileCallback) {
|
|
2515
|
+
let stop = false;
|
|
2516
|
+
let zipEntryCount = 0;
|
|
2517
|
+
do {
|
|
2518
|
+
const zipHeader = await this.readLocalFileHeader();
|
|
2519
|
+
if (!zipHeader) break;
|
|
2520
|
+
zipEntryCount++;
|
|
2521
|
+
if (zipEntryCount > maximumZipEntryCount) throw new Error(`ZIP entry count exceeds ${maximumZipEntryCount}`);
|
|
2522
|
+
const next = fileCallback(zipHeader);
|
|
2523
|
+
stop = Boolean(next.stop);
|
|
2524
|
+
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
2525
|
+
const fileData = await readZipEntryData(this, zipHeader, { shouldBuffer: Boolean(next.handler) });
|
|
2526
|
+
if (next.handler) await this.inflate(zipHeader, fileData, next.handler);
|
|
2527
|
+
if (zipHeader.dataDescriptor) {
|
|
2528
|
+
const dataDescriptor = new Uint8Array(zipDataDescriptorLengthInBytes);
|
|
2529
|
+
await this.tokenizer.readBuffer(dataDescriptor);
|
|
2530
|
+
if (UINT32_LE.get(dataDescriptor, 0) !== zipDataDescriptorSignature) throw new Error(`Expected data-descriptor-signature at position ${this.tokenizer.position - dataDescriptor.length}`);
|
|
2531
|
+
}
|
|
2532
|
+
} while (!stop);
|
|
2447
2533
|
};
|
|
2448
2534
|
function createByteLimitedReadableStream(stream, maximumBytes) {
|
|
2449
2535
|
const reader = stream.getReader();
|
|
@@ -2622,12 +2708,17 @@ function hasUnknownFileSize(tokenizer) {
|
|
|
2622
2708
|
function hasExceededUnknownSizeScanBudget(tokenizer, startOffset, maximumBytes) {
|
|
2623
2709
|
return hasUnknownFileSize(tokenizer) && tokenizer.position - startOffset > maximumBytes;
|
|
2624
2710
|
}
|
|
2711
|
+
function getMaximumZipBufferedReadLength(tokenizer) {
|
|
2712
|
+
const fileSize = tokenizer.fileInfo.size;
|
|
2713
|
+
const remainingBytes = Number.isFinite(fileSize) ? Math.max(0, fileSize - tokenizer.position) : Number.MAX_SAFE_INTEGER;
|
|
2714
|
+
return Math.min(remainingBytes, maximumZipBufferedReadSizeInBytes);
|
|
2715
|
+
}
|
|
2625
2716
|
function isRecoverableZipError(error) {
|
|
2626
2717
|
if (error instanceof EndOfStreamError) return true;
|
|
2627
2718
|
if (error instanceof ParserHardLimitError) return true;
|
|
2628
2719
|
if (!(error instanceof Error)) return false;
|
|
2629
2720
|
if (recoverableZipErrorMessages.has(error.message)) return true;
|
|
2630
|
-
if (
|
|
2721
|
+
if (recoverableZipErrorCodes.has(error.code)) return true;
|
|
2631
2722
|
for (const prefix of recoverableZipErrorMessagePrefixes) if (error.message.startsWith(prefix)) return true;
|
|
2632
2723
|
return false;
|
|
2633
2724
|
}
|
|
@@ -2703,8 +2794,13 @@ var FileTypeParser = class {
|
|
|
2703
2794
|
}
|
|
2704
2795
|
];
|
|
2705
2796
|
this.tokenizerOptions = { abortSignal: this.options.signal };
|
|
2797
|
+
this.gzipProbeDepth = 0;
|
|
2706
2798
|
}
|
|
2707
|
-
|
|
2799
|
+
getTokenizerOptions() {
|
|
2800
|
+
return { ...this.tokenizerOptions };
|
|
2801
|
+
}
|
|
2802
|
+
async fromTokenizer(tokenizer, detectionReentryCount = 0) {
|
|
2803
|
+
this.detectionReentryCount = detectionReentryCount;
|
|
2708
2804
|
const initialPosition = tokenizer.position;
|
|
2709
2805
|
for (const detector of this.detectors) {
|
|
2710
2806
|
let fileType;
|
|
@@ -2723,10 +2819,10 @@ var FileTypeParser = class {
|
|
|
2723
2819
|
if (!(input instanceof Uint8Array || input instanceof ArrayBuffer)) throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof input}\``);
|
|
2724
2820
|
const buffer = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
2725
2821
|
if (!(buffer?.length > 1)) return;
|
|
2726
|
-
return this.fromTokenizer(fromBuffer(buffer, this.
|
|
2822
|
+
return this.fromTokenizer(fromBuffer(buffer, this.getTokenizerOptions()));
|
|
2727
2823
|
}
|
|
2728
2824
|
async fromBlob(blob) {
|
|
2729
|
-
const tokenizer = fromBlob(blob, this.
|
|
2825
|
+
const tokenizer = fromBlob(blob, this.getTokenizerOptions());
|
|
2730
2826
|
try {
|
|
2731
2827
|
return await this.fromTokenizer(tokenizer);
|
|
2732
2828
|
} finally {
|
|
@@ -2734,7 +2830,7 @@ var FileTypeParser = class {
|
|
|
2734
2830
|
}
|
|
2735
2831
|
}
|
|
2736
2832
|
async fromStream(stream) {
|
|
2737
|
-
const tokenizer = fromWebStream(stream, this.
|
|
2833
|
+
const tokenizer = fromWebStream(stream, this.getTokenizerOptions());
|
|
2738
2834
|
try {
|
|
2739
2835
|
return await this.fromTokenizer(tokenizer);
|
|
2740
2836
|
} finally {
|
|
@@ -2832,6 +2928,8 @@ var FileTypeParser = class {
|
|
|
2832
2928
|
187,
|
|
2833
2929
|
191
|
|
2834
2930
|
])) {
|
|
2931
|
+
if (this.detectionReentryCount >= maximumDetectionReentryCount) return;
|
|
2932
|
+
this.detectionReentryCount++;
|
|
2835
2933
|
await this.tokenizer.ignore(3);
|
|
2836
2934
|
return this.detectConfident(tokenizer);
|
|
2837
2935
|
}
|
|
@@ -2856,12 +2954,19 @@ var FileTypeParser = class {
|
|
|
2856
2954
|
139,
|
|
2857
2955
|
8
|
|
2858
2956
|
])) {
|
|
2957
|
+
if (this.gzipProbeDepth >= maximumNestedGzipProbeDepth) return {
|
|
2958
|
+
ext: "gz",
|
|
2959
|
+
mime: "application/gzip"
|
|
2960
|
+
};
|
|
2859
2961
|
const limitedInflatedStream = createByteLimitedReadableStream(new GzipHandler(tokenizer).inflate(), maximumNestedGzipDetectionSizeInBytes);
|
|
2860
2962
|
let compressedFileType;
|
|
2861
2963
|
try {
|
|
2964
|
+
this.gzipProbeDepth++;
|
|
2862
2965
|
compressedFileType = await this.fromStream(limitedInflatedStream);
|
|
2863
2966
|
} catch (error) {
|
|
2864
2967
|
if (error?.name === "AbortError") throw error;
|
|
2968
|
+
} finally {
|
|
2969
|
+
this.gzipProbeDepth--;
|
|
2865
2970
|
}
|
|
2866
2971
|
if (compressedFileType?.ext === "tar") return {
|
|
2867
2972
|
ext: "tar.gz",
|
|
@@ -2904,7 +3009,9 @@ var FileTypeParser = class {
|
|
|
2904
3009
|
if (error instanceof EndOfStreamError) return;
|
|
2905
3010
|
throw error;
|
|
2906
3011
|
}
|
|
2907
|
-
|
|
3012
|
+
if (this.detectionReentryCount >= maximumDetectionReentryCount) return;
|
|
3013
|
+
this.detectionReentryCount++;
|
|
3014
|
+
return this.fromTokenizer(tokenizer, this.detectionReentryCount);
|
|
2908
3015
|
}
|
|
2909
3016
|
if (this.checkString("MP+")) return {
|
|
2910
3017
|
ext: "mpc",
|
|
@@ -2988,7 +3095,7 @@ var FileTypeParser = class {
|
|
|
2988
3095
|
};
|
|
2989
3096
|
return { stop: true };
|
|
2990
3097
|
case "mimetype":
|
|
2991
|
-
if (!canReadZipEntryForDetection(zipHeader)) return {};
|
|
3098
|
+
if (!canReadZipEntryForDetection(zipHeader, maximumZipTextEntrySizeInBytes)) return {};
|
|
2992
3099
|
return {
|
|
2993
3100
|
async handler(fileData) {
|
|
2994
3101
|
fileType = getFileTypeFromMimeType(new TextDecoder("utf-8").decode(fileData).trim());
|
|
@@ -2997,7 +3104,7 @@ var FileTypeParser = class {
|
|
|
2997
3104
|
};
|
|
2998
3105
|
case "[Content_Types].xml":
|
|
2999
3106
|
openXmlState.hasContentTypesEntry = true;
|
|
3000
|
-
if (!canReadZipEntryForDetection(zipHeader,
|
|
3107
|
+
if (!canReadZipEntryForDetection(zipHeader, maximumZipTextEntrySizeInBytes)) {
|
|
3001
3108
|
openXmlState.hasUnparseableContentTypes = true;
|
|
3002
3109
|
return {};
|
|
3003
3110
|
}
|
|
@@ -3242,6 +3349,7 @@ var FileTypeParser = class {
|
|
|
3242
3349
|
while (children > 0) {
|
|
3243
3350
|
ebmlElementCount++;
|
|
3244
3351
|
if (ebmlElementCount > maximumEbmlElementCount) return;
|
|
3352
|
+
const previousPosition = tokenizer.position;
|
|
3245
3353
|
const element = await readElement();
|
|
3246
3354
|
if (element.id === 17026) {
|
|
3247
3355
|
if (element.len > maximumEbmlDocumentTypeSizeInBytes) return;
|
|
@@ -3254,6 +3362,7 @@ var FileTypeParser = class {
|
|
|
3254
3362
|
reason: "EBML payload"
|
|
3255
3363
|
});
|
|
3256
3364
|
--children;
|
|
3365
|
+
if (tokenizer.position <= previousPosition) return;
|
|
3257
3366
|
}
|
|
3258
3367
|
}
|
|
3259
3368
|
switch (await readChildren((await readElement()).len)) {
|
|
@@ -3572,8 +3681,12 @@ var FileTypeParser = class {
|
|
|
3572
3681
|
}
|
|
3573
3682
|
const isUnknownPngStream = hasUnknownFileSize(tokenizer);
|
|
3574
3683
|
const pngScanStart = tokenizer.position;
|
|
3684
|
+
let pngChunkCount = 0;
|
|
3575
3685
|
do {
|
|
3686
|
+
pngChunkCount++;
|
|
3687
|
+
if (pngChunkCount > maximumPngChunkCount) break;
|
|
3576
3688
|
if (hasExceededUnknownSizeScanBudget(tokenizer, pngScanStart, maximumPngChunkSizeInBytes)) break;
|
|
3689
|
+
const previousPosition = tokenizer.position;
|
|
3577
3690
|
const chunk = await readChunkHeader();
|
|
3578
3691
|
if (chunk.length < 0) return;
|
|
3579
3692
|
switch (chunk.type) {
|
|
@@ -3591,6 +3704,7 @@ var FileTypeParser = class {
|
|
|
3591
3704
|
throw error;
|
|
3592
3705
|
}
|
|
3593
3706
|
}
|
|
3707
|
+
if (tokenizer.position <= previousPosition) break;
|
|
3594
3708
|
} while (tokenizer.position + 8 < tokenizer.fileInfo.size);
|
|
3595
3709
|
return pngFileType;
|
|
3596
3710
|
}
|
|
@@ -3836,7 +3950,10 @@ var FileTypeParser = class {
|
|
|
3836
3950
|
});
|
|
3837
3951
|
const isUnknownFileSize = hasUnknownFileSize(tokenizer);
|
|
3838
3952
|
const asfHeaderScanStart = tokenizer.position;
|
|
3953
|
+
let asfHeaderObjectCount = 0;
|
|
3839
3954
|
while (tokenizer.position + 24 < tokenizer.fileInfo.size) {
|
|
3955
|
+
asfHeaderObjectCount++;
|
|
3956
|
+
if (asfHeaderObjectCount > maximumAsfHeaderObjectCount) break;
|
|
3840
3957
|
if (hasExceededUnknownSizeScanBudget(tokenizer, asfHeaderScanStart, maximumUntrustedSkipSizeInBytes)) break;
|
|
3841
3958
|
const previousPosition = tokenizer.position;
|
|
3842
3959
|
const header = await readHeader();
|
|
@@ -4419,6 +4536,7 @@ var FileTypeParser = class {
|
|
|
4419
4536
|
}
|
|
4420
4537
|
async readTiffIFD(bigEndian) {
|
|
4421
4538
|
const numberOfTags = await this.tokenizer.readToken(bigEndian ? UINT16_BE : UINT16_LE);
|
|
4539
|
+
if (numberOfTags > maximumTiffTagCount) return;
|
|
4422
4540
|
if (hasUnknownFileSize(this.tokenizer) && 2 + numberOfTags * 12 > maximumTiffIfdOffsetInBytes) return;
|
|
4423
4541
|
for (let n = 0; n < numberOfTags; ++n) {
|
|
4424
4542
|
const fileType = await this.readTiffTag(bigEndian);
|
|
@@ -4524,4 +4642,4 @@ const supportedMimeTypes = new Set(mimeTypes);
|
|
|
4524
4642
|
|
|
4525
4643
|
//#endregion
|
|
4526
4644
|
export { fileTypeFromBlob };
|
|
4527
|
-
//# sourceMappingURL=file-type-
|
|
4645
|
+
//# sourceMappingURL=file-type-DlzWawJh.mjs.map
|