@patrickdk77/archive-defuse 0.1.1 → 0.1.3
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/README.md +23 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.mjs +1 -1
- package/dist/lzma1/NOTICE +32 -18
- package/dist/lzma1/crc32.d.ts +2 -1
- package/dist/lzma1/crc32.js +3 -2
- package/dist/lzma1/hash234.d.ts +3 -1
- package/dist/lzma1/hash234.js +9 -4
- package/dist/lzma1/hc4.d.ts +3 -2
- package/dist/lzma1/hc4.js +6 -4
- package/dist/lzma1/header.js +1 -1
- package/dist/lzma1/lz-decoder.d.ts +14 -14
- package/dist/lzma1/lz-decoder.js +15 -33
- package/dist/lzma1/lz-encoder.d.ts +3 -2
- package/dist/lzma1/lz-encoder.js +6 -4
- package/dist/lzma1/lzma-coder.d.ts +51 -27
- package/dist/lzma1/lzma-coder.js +114 -48
- package/dist/lzma1/lzma-decoder.d.ts +41 -19
- package/dist/lzma1/lzma-decoder.js +159 -437
- package/dist/lzma1/lzma-encoder-fast.d.ts +2 -1
- package/dist/lzma1/lzma-encoder-fast.js +3 -2
- package/dist/lzma1/lzma-encoder.d.ts +68 -40
- package/dist/lzma1/lzma-encoder.js +289 -232
- package/dist/lzma1/lzma2-decoder.d.ts +17 -2
- package/dist/lzma1/lzma2-decoder.js +71 -15
- package/dist/lzma1/range-coder.d.ts +4 -0
- package/dist/lzma1/range-coder.js +5 -1
- package/dist/lzma1/range-decoder.d.ts +22 -22
- package/dist/lzma1/range-decoder.js +74 -32
- package/dist/lzma1/range-encoder.d.ts +26 -28
- package/dist/lzma1/range-encoder.js +98 -150
- package/dist/pack.d.ts +39 -3
- package/dist/pack.js +173 -17
- package/dist/zip-writer.d.ts +7 -3
- package/dist/zip-writer.js +18 -11
- package/package.json +1 -1
package/dist/pack.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.PackError = void 0;
|
|
|
4
4
|
exports.createArchive = createArchive;
|
|
5
5
|
exports.createArchiveStream = createArchiveStream;
|
|
6
6
|
exports.createArchiveBytes = createArchiveBytes;
|
|
7
|
+
exports.createArchiveWriter = createArchiveWriter;
|
|
7
8
|
exports.compressTo = compressTo;
|
|
8
9
|
exports.compressStream = compressStream;
|
|
9
10
|
exports.compress = compress;
|
|
@@ -119,6 +120,12 @@ function settle(entry, options, now) {
|
|
|
119
120
|
const kind = entry.kind ?? (raw.endsWith('/') ? 'directory' : entry.linkTarget !== undefined ? 'symlink' : 'file');
|
|
120
121
|
if (kind === 'symlink' && entry.linkTarget === undefined)
|
|
121
122
|
throw new PackError(`Symbolic link ${JSON.stringify(raw)} needs a linkTarget`);
|
|
123
|
+
if (entry.size !== undefined) {
|
|
124
|
+
if (kind !== 'file')
|
|
125
|
+
throw new PackError(`Entry ${JSON.stringify(raw)} is a ${kind}, and only a file takes a size`);
|
|
126
|
+
if (!Number.isSafeInteger(entry.size) || entry.size < 0)
|
|
127
|
+
throw new PackError(`Entry ${JSON.stringify(raw)} has a size of ${String(entry.size)}, which is not a whole number of bytes`);
|
|
128
|
+
}
|
|
122
129
|
const name = kind === 'directory' ? (raw.endsWith('/') ? raw : `${raw}/`) : raw.replace(/\/+$/, '');
|
|
123
130
|
for (const detail of (0, rules_1.nameDetails)(name, true)) {
|
|
124
131
|
const why = REFUSED[detail];
|
|
@@ -135,21 +142,51 @@ function settle(entry, options, now) {
|
|
|
135
142
|
}
|
|
136
143
|
return { name, kind, entry, mode: (entry.mode ?? (kind === 'directory' ? 0o755 : kind === 'symlink' ? 0o777 : 0o644)) & 0o7777, mtime: entry.mtime ?? options.mtime ?? now };
|
|
137
144
|
}
|
|
138
|
-
/**
|
|
145
|
+
/** `chunks`, failing as soon as they pass `size` bytes, or when they end short of it. */
|
|
146
|
+
async function* sized(chunks, size, name) {
|
|
147
|
+
let total = 0;
|
|
148
|
+
for await (const c of chunks) {
|
|
149
|
+
total += c.length;
|
|
150
|
+
if (total > size)
|
|
151
|
+
throw new Error(`Entry ${JSON.stringify(name)} has more than the ${size} bytes its size gives`);
|
|
152
|
+
yield c;
|
|
153
|
+
}
|
|
154
|
+
if (total !== size)
|
|
155
|
+
throw new Error(`Entry ${JSON.stringify(name)} has ${total} bytes, not the ${size} its size gives`);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The content of a settled entry: a file's data, a link's target, or nothing for a folder. A file's size is known when
|
|
159
|
+
* the entry gives one or its content is bytes or text. Content given as bytes or text of another size than the entry
|
|
160
|
+
* gives throws a PackError here, before the entry is written; a stream of another size fails as it is read.
|
|
161
|
+
*/
|
|
139
162
|
async function contentOf(s) {
|
|
140
163
|
if (s.kind === 'directory')
|
|
141
|
-
return chunksOf(undefined);
|
|
142
|
-
if (s.kind === 'symlink')
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
164
|
+
return { chunks: chunksOf(undefined), size: 0 };
|
|
165
|
+
if (s.kind === 'symlink') {
|
|
166
|
+
const target = toBytes(s.entry.linkTarget ?? '');
|
|
167
|
+
return { chunks: chunksOf(target), size: target.length };
|
|
168
|
+
}
|
|
169
|
+
const given = s.entry.data;
|
|
170
|
+
const raw = typeof given === 'function' ? await given() : given;
|
|
171
|
+
const data = typeof raw === 'string' ? toBytes(raw) : raw;
|
|
172
|
+
const own = data === undefined ? 0 : data instanceof Uint8Array ? data.length : undefined;
|
|
173
|
+
const size = s.entry.size;
|
|
174
|
+
if (size === undefined)
|
|
175
|
+
return { chunks: chunksOf(data), size: own };
|
|
176
|
+
if (own !== undefined && own !== size)
|
|
177
|
+
throw new PackError(`Entry ${JSON.stringify(s.name)} holds ${own} bytes, not the ${size} its size gives`);
|
|
178
|
+
return { chunks: sized(chunksOf(data), size, s.name), size };
|
|
146
179
|
}
|
|
147
180
|
/** Reads an entry's content into memory or a temporary file, counting its CRC-32. */
|
|
148
181
|
async function spillOf(s, temp, threshold, check) {
|
|
182
|
+
return spillChunks((await contentOf(s)).chunks, temp, threshold, check);
|
|
183
|
+
}
|
|
184
|
+
/** Reads chunks into memory or a temporary file, counting their CRC-32. */
|
|
185
|
+
async function spillChunks(chunks, temp, threshold, check) {
|
|
149
186
|
const spill = new io_1.SpillSink(temp, threshold);
|
|
150
187
|
let crc = 0;
|
|
151
188
|
try {
|
|
152
|
-
for await (const c of checked(
|
|
189
|
+
for await (const c of checked(chunks, check)) {
|
|
153
190
|
crc = (0, crc32_1.crc32)(c, crc);
|
|
154
191
|
await spill.write(c);
|
|
155
192
|
}
|
|
@@ -236,7 +273,8 @@ async function writeZipEntries(entries, sink, options, temp, check) {
|
|
|
236
273
|
* second, hidden entry gets past a reader of the central directory.
|
|
237
274
|
*/
|
|
238
275
|
async function streamZipEntry(out, s, info, level, check) {
|
|
239
|
-
const
|
|
276
|
+
const content = await contentOf(s);
|
|
277
|
+
const it = checked(content.chunks, check)[Symbol.asyncIterator]();
|
|
240
278
|
let first;
|
|
241
279
|
try {
|
|
242
280
|
first = await it.next();
|
|
@@ -277,7 +315,9 @@ async function streamZipEntry(out, s, info, level, check) {
|
|
|
277
315
|
}
|
|
278
316
|
};
|
|
279
317
|
Object.assign(info, { method: 8, versionNeeded: 20 });
|
|
280
|
-
|
|
318
|
+
// zlib's deflateBound for any settings: deflate never grows data by more than this.
|
|
319
|
+
const zip64 = content.size !== undefined && content.size + Math.ceil(content.size / 8) + Math.ceil(content.size / 64) + 5 >= 0xffffffff;
|
|
320
|
+
await out.streamEntry(info, (0, codecs_1.deflateRaw)(raw(), level), () => ({ crc, size }), zip64);
|
|
281
321
|
}
|
|
282
322
|
// ---------------------------------------------------------------------------------------------------------------
|
|
283
323
|
// tar
|
|
@@ -287,9 +327,25 @@ async function* tarChunks(entries, options, temp, check) {
|
|
|
287
327
|
let written = 0;
|
|
288
328
|
const pad = (n) => Buffer.alloc((tar_1.BLOCK - (n % tar_1.BLOCK)) % tar_1.BLOCK);
|
|
289
329
|
for await (const s of entries) {
|
|
290
|
-
|
|
330
|
+
let spill;
|
|
331
|
+
let direct;
|
|
332
|
+
let first;
|
|
333
|
+
let size = 0;
|
|
291
334
|
try {
|
|
292
|
-
|
|
335
|
+
if (s.kind === 'file') {
|
|
336
|
+
const content = await contentOf(s);
|
|
337
|
+
if (content.size === undefined) {
|
|
338
|
+
({ spill } = await spillChunks(content.chunks, temp, threshold, check));
|
|
339
|
+
size = spill.length;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
// The header can go first and the data straight after it. The first chunk is read before the header, so a
|
|
343
|
+
// stream that fails at once fails before its entry is begun, and a stream is open to close should the work stop.
|
|
344
|
+
size = content.size;
|
|
345
|
+
direct = checked(content.chunks, check)[Symbol.asyncIterator]();
|
|
346
|
+
first = await direct.next();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
293
349
|
const link = s.kind === 'symlink' ? (s.entry.linkTarget ?? '') : '';
|
|
294
350
|
const mtime = Math.floor(s.mtime.getTime() / 1000);
|
|
295
351
|
// What the ustar header cannot hold goes in a pax header before it.
|
|
@@ -344,8 +400,13 @@ async function* tarChunks(entries, options, temp, check) {
|
|
|
344
400
|
});
|
|
345
401
|
yield h;
|
|
346
402
|
written += h.length;
|
|
347
|
-
if (spill)
|
|
403
|
+
if (spill)
|
|
348
404
|
yield* checked(spill.read(), check);
|
|
405
|
+
if (direct && first) {
|
|
406
|
+
for (let r = first; !r.done; r = await direct.next())
|
|
407
|
+
yield r.value;
|
|
408
|
+
}
|
|
409
|
+
if (spill || direct) {
|
|
349
410
|
const p = pad(size);
|
|
350
411
|
if (p.length)
|
|
351
412
|
yield p;
|
|
@@ -353,6 +414,7 @@ async function* tarChunks(entries, options, temp, check) {
|
|
|
353
414
|
}
|
|
354
415
|
}
|
|
355
416
|
finally {
|
|
417
|
+
await direct?.return?.(undefined);
|
|
356
418
|
await spill?.dispose();
|
|
357
419
|
}
|
|
358
420
|
}
|
|
@@ -476,6 +538,15 @@ function compressChunks(format, input, options, temp, now, check) {
|
|
|
476
538
|
// The calls
|
|
477
539
|
const ARCHIVE_FORMATS = new Set(['zip', 'tar', 'tar.gz', 'tar.bz2', 'tar.zst', 'tar.xz', '7z']);
|
|
478
540
|
const TAR_COMPRESSION = { 'tar.gz': 'gzip', 'tar.bz2': 'bzip2', 'tar.zst': 'zstd', 'tar.xz': 'xz' };
|
|
541
|
+
/** Throws for a format `createArchive` does not write, and for `streaming` with any format but ZIP. */
|
|
542
|
+
function checkFormat(format, options) {
|
|
543
|
+
if (!ARCHIVE_FORMATS.has(format))
|
|
544
|
+
throw new PackError(`Unknown archive format ${String(format)}`);
|
|
545
|
+
// tar writes a file of known size as it arrives without the option, and needs the size of any other first. 7z writes
|
|
546
|
+
// its header from every entry after the data.
|
|
547
|
+
if (options.streaming && format !== 'zip')
|
|
548
|
+
throw new PackError(`streaming writes ZIP archives only, not ${format}`);
|
|
549
|
+
}
|
|
479
550
|
/** Copies chunks to the sink, then closes it. On failure it aborts the sink, so a partial output never looks whole. */
|
|
480
551
|
async function deliver(produce, sink) {
|
|
481
552
|
try {
|
|
@@ -498,11 +569,7 @@ async function deliver(produce, sink) {
|
|
|
498
569
|
* sink is aborted instead of closed and the error is thrown.
|
|
499
570
|
*/
|
|
500
571
|
async function createArchive(format, entries, sink, options = {}) {
|
|
501
|
-
|
|
502
|
-
throw new PackError(`Unknown archive format ${String(format)}`);
|
|
503
|
-
// tar needs each entry's size before its data, and 7z writes its header from every entry after the data.
|
|
504
|
-
if (options.streaming && format !== 'zip')
|
|
505
|
-
throw new PackError(`streaming writes ZIP archives only, not ${format}`);
|
|
572
|
+
checkFormat(format, options);
|
|
506
573
|
const now = new Date();
|
|
507
574
|
const temp = new io_1.TempDir(options.tempDir);
|
|
508
575
|
const check = () => options.signal?.throwIfAborted();
|
|
@@ -563,6 +630,95 @@ async function createArchiveBytes(format, entries, options = {}) {
|
|
|
563
630
|
await createArchive(format, entries, sink, options);
|
|
564
631
|
return sink.result();
|
|
565
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* `createArchiveStream` for a caller that finds its entries as it goes. An entry `createArchive` refuses, or data that
|
|
635
|
+
* fails, fails the archive: `finish` rejects with the error and `stream` is destroyed with it.
|
|
636
|
+
*/
|
|
637
|
+
function createArchiveWriter(format, options = {}) {
|
|
638
|
+
checkFormat(format, options);
|
|
639
|
+
const queue = [];
|
|
640
|
+
let head = 0;
|
|
641
|
+
let closed;
|
|
642
|
+
let failure;
|
|
643
|
+
let wake;
|
|
644
|
+
const drop = () => {
|
|
645
|
+
queue.length = 0;
|
|
646
|
+
head = 0;
|
|
647
|
+
};
|
|
648
|
+
const stop = new AbortController();
|
|
649
|
+
const outer = options.signal;
|
|
650
|
+
const forward = () => stop.abort(outer?.reason);
|
|
651
|
+
if (outer?.aborted)
|
|
652
|
+
forward();
|
|
653
|
+
else
|
|
654
|
+
outer?.addEventListener('abort', forward, { once: true });
|
|
655
|
+
// The loop waits here for the next entry. The wait ends when the work stops, so a reader that goes away or an abort
|
|
656
|
+
// does not leave it waiting for an entry that never comes.
|
|
657
|
+
const nextEntry = (signal) => new Promise((resolve, reject) => {
|
|
658
|
+
const stopped = () => {
|
|
659
|
+
wake = undefined;
|
|
660
|
+
reject(signal.reason);
|
|
661
|
+
};
|
|
662
|
+
signal.addEventListener('abort', stopped, { once: true });
|
|
663
|
+
wake = () => {
|
|
664
|
+
signal.removeEventListener('abort', stopped);
|
|
665
|
+
wake = undefined;
|
|
666
|
+
resolve();
|
|
667
|
+
};
|
|
668
|
+
});
|
|
669
|
+
async function* entries(signal) {
|
|
670
|
+
for (;;) {
|
|
671
|
+
if (head < queue.length) {
|
|
672
|
+
const e = queue[head];
|
|
673
|
+
queue[head++] = undefined;
|
|
674
|
+
if (head === queue.length)
|
|
675
|
+
drop();
|
|
676
|
+
if (e)
|
|
677
|
+
yield e;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (closed === 'finished')
|
|
681
|
+
return;
|
|
682
|
+
signal.throwIfAborted();
|
|
683
|
+
await nextEntry(signal);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
let done = Promise.resolve();
|
|
687
|
+
const stream = readableOf((sink, signal) => {
|
|
688
|
+
done = createArchive(format, entries(signal), sink, { ...options, signal });
|
|
689
|
+
return done;
|
|
690
|
+
}, stop.signal);
|
|
691
|
+
done.then(() => outer?.removeEventListener('abort', forward), error => {
|
|
692
|
+
failure ??= { error };
|
|
693
|
+
drop();
|
|
694
|
+
outer?.removeEventListener('abort', forward);
|
|
695
|
+
});
|
|
696
|
+
return {
|
|
697
|
+
stream,
|
|
698
|
+
add(entry) {
|
|
699
|
+
if (closed)
|
|
700
|
+
throw new PackError(`An entry was added after the archive was ${closed}`);
|
|
701
|
+
if (failure)
|
|
702
|
+
throw new PackError('An entry was added after the archive failed', { cause: failure.error });
|
|
703
|
+
queue.push(entry);
|
|
704
|
+
wake?.();
|
|
705
|
+
},
|
|
706
|
+
finish() {
|
|
707
|
+
if (!closed) {
|
|
708
|
+
closed = 'finished';
|
|
709
|
+
wake?.();
|
|
710
|
+
}
|
|
711
|
+
return done;
|
|
712
|
+
},
|
|
713
|
+
abort(reason) {
|
|
714
|
+
if (closed === 'aborted')
|
|
715
|
+
return;
|
|
716
|
+
closed = 'aborted';
|
|
717
|
+
drop();
|
|
718
|
+
stop.abort(reason);
|
|
719
|
+
},
|
|
720
|
+
};
|
|
721
|
+
}
|
|
566
722
|
/** Compresses `data` as one stream of `format` to `sink`, then closes it. */
|
|
567
723
|
async function compressTo(format, data, sink, options = {}) {
|
|
568
724
|
const temp = new io_1.TempDir(options.tempDir);
|
package/dist/zip-writer.d.ts
CHANGED
|
@@ -37,13 +37,17 @@ export declare class ZipOutput {
|
|
|
37
37
|
/**
|
|
38
38
|
* Writes one entry whose sizes are known only once its data has gone out: a local header with the data descriptor
|
|
39
39
|
* flag and no CRC or sizes, then `chunks`, the compressed data, then a data descriptor with the CRC and the sizes.
|
|
40
|
-
* `totals` gives the CRC and size of the uncompressed data once `chunks` has ended.
|
|
41
|
-
*
|
|
40
|
+
* `totals` gives the CRC and size of the uncompressed data once `chunks` has ended.
|
|
41
|
+
*
|
|
42
|
+
* With `zip64`, the local header has a ZIP64 field, which tells a reader the descriptor's sizes are eight bytes. Its
|
|
43
|
+
* sizes are 0xFFFFFFFF and the field's are zero, as Python's zipfile writes a streamed entry. Without it, an entry of
|
|
44
|
+
* 4 GiB or more still gets eight-byte sizes in its descriptor, as archiver writes one. Either way, the central
|
|
45
|
+
* directory has a ZIP64 field only when a size or the offset needs one.
|
|
42
46
|
*/
|
|
43
47
|
streamEntry(info: Written, chunks: AsyncIterable<Uint8Array>, totals: () => {
|
|
44
48
|
crc: number;
|
|
45
49
|
size: number;
|
|
46
|
-
}): Promise<void>;
|
|
50
|
+
}, zip64?: boolean): Promise<void>;
|
|
47
51
|
/** Writes the central directory and the end records, with the archive's comment. */
|
|
48
52
|
end(comment: Uint8Array): Promise<void>;
|
|
49
53
|
}
|
package/dist/zip-writer.js
CHANGED
|
@@ -89,26 +89,33 @@ class ZipOutput {
|
|
|
89
89
|
/**
|
|
90
90
|
* Writes one entry whose sizes are known only once its data has gone out: a local header with the data descriptor
|
|
91
91
|
* flag and no CRC or sizes, then `chunks`, the compressed data, then a data descriptor with the CRC and the sizes.
|
|
92
|
-
* `totals` gives the CRC and size of the uncompressed data once `chunks` has ended.
|
|
93
|
-
*
|
|
92
|
+
* `totals` gives the CRC and size of the uncompressed data once `chunks` has ended.
|
|
93
|
+
*
|
|
94
|
+
* With `zip64`, the local header has a ZIP64 field, which tells a reader the descriptor's sizes are eight bytes. Its
|
|
95
|
+
* sizes are 0xFFFFFFFF and the field's are zero, as Python's zipfile writes a streamed entry. Without it, an entry of
|
|
96
|
+
* 4 GiB or more still gets eight-byte sizes in its descriptor, as archiver writes one. Either way, the central
|
|
97
|
+
* directory has a ZIP64 field only when a size or the offset needs one.
|
|
94
98
|
*/
|
|
95
|
-
async streamEntry(info, chunks, totals) {
|
|
99
|
+
async streamEntry(info, chunks, totals, zip64 = false) {
|
|
96
100
|
const flags = info.flags | 0x0008;
|
|
101
|
+
const versionNeeded = zip64 ? Math.max(45, info.versionNeeded) : info.versionNeeded;
|
|
97
102
|
const localOffset = this.offset;
|
|
98
103
|
const local = new Builder()
|
|
99
104
|
.u32(0x04034b50)
|
|
100
|
-
.u16(
|
|
105
|
+
.u16(versionNeeded)
|
|
101
106
|
.u16(flags)
|
|
102
107
|
.u16(info.method)
|
|
103
108
|
.u16(info.time)
|
|
104
109
|
.u16(info.date)
|
|
105
110
|
.u32(0)
|
|
106
|
-
.u32(0)
|
|
107
|
-
.u32(0)
|
|
111
|
+
.u32(zip64 ? MAX32 : 0)
|
|
112
|
+
.u32(zip64 ? MAX32 : 0)
|
|
108
113
|
.u16(info.name.length)
|
|
109
|
-
.u16(info.extras.length)
|
|
110
|
-
.bytes(info.name)
|
|
111
|
-
|
|
114
|
+
.u16(info.extras.length + (zip64 ? 20 : 0))
|
|
115
|
+
.bytes(info.name);
|
|
116
|
+
if (zip64)
|
|
117
|
+
local.u16(0x0001).u16(16).u64(0).u64(0);
|
|
118
|
+
local.bytes(info.extras);
|
|
112
119
|
await this.put(local.build());
|
|
113
120
|
let compressedSize = 0;
|
|
114
121
|
for await (const c of chunks) {
|
|
@@ -117,12 +124,12 @@ class ZipOutput {
|
|
|
117
124
|
}
|
|
118
125
|
const { crc, size } = totals();
|
|
119
126
|
const descriptor = new Builder().u32(0x08074b50).u32(crc);
|
|
120
|
-
if (size >= MAX32 || compressedSize >= MAX32)
|
|
127
|
+
if (zip64 || size >= MAX32 || compressedSize >= MAX32)
|
|
121
128
|
descriptor.u64(compressedSize).u64(size);
|
|
122
129
|
else
|
|
123
130
|
descriptor.u32(compressedSize).u32(size);
|
|
124
131
|
await this.put(descriptor.build());
|
|
125
|
-
this.central.push(centralRecord({ ...info, flags, crc, size, compressedSize }, localOffset));
|
|
132
|
+
this.central.push(centralRecord({ ...info, versionNeeded, flags, crc, size, compressedSize }, localOffset));
|
|
126
133
|
}
|
|
127
134
|
/** Writes the central directory and the end records, with the archive's comment. */
|
|
128
135
|
async end(comment) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patrickdk77/archive-defuse",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Sanitize zip, tar, gzip, bzip2, zstd, Brotli, cab, 7z, xz and lzma archives. Detects path traversal, links out of the tree, device files, duplicate names, overlapping entries, hidden and prepended data, encrypted entries and compression bombs, hands every entry to file plugins, scores the risk, and writes a defused archive in the same format with no runtime dependencies.",
|
|
5
5
|
"license": "MIT AND Apache-2.0",
|
|
6
6
|
"author": "patrickdk77",
|