@patrickdk77/archive-defuse 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +345 -2
- package/dist/aes7z.d.ts +16 -0
- package/dist/aes7z.js +131 -0
- package/dist/alone.d.ts +21 -0
- package/dist/alone.js +65 -0
- package/dist/bcj2.d.ts +21 -0
- package/dist/bcj2.js +140 -0
- package/dist/bzip2.d.ts +21 -0
- package/dist/bzip2.js +688 -0
- package/dist/cab.d.ts +63 -0
- package/dist/cab.js +493 -0
- package/dist/checks.d.ts +23 -0
- package/dist/checks.js +123 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +364 -0
- package/dist/codecs.d.ts +39 -0
- package/dist/codecs.js +124 -0
- package/dist/coders.d.ts +58 -0
- package/dist/coders.js +392 -0
- package/dist/crc32.d.ts +8 -0
- package/dist/crc32.js +59 -0
- package/dist/encoder.d.ts +44 -0
- package/dist/encoder.js +114 -0
- package/dist/engine.d.ts +44 -0
- package/dist/engine.js +753 -0
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +98 -0
- package/dist/filters.d.ts +34 -0
- package/dist/filters.js +385 -0
- package/dist/findings.d.ts +26 -0
- package/dist/findings.js +176 -0
- package/dist/formats.d.ts +14 -0
- package/dist/formats.js +97 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +50 -0
- package/dist/index.mjs +3 -0
- package/dist/inflate64.d.ts +6 -0
- package/dist/inflate64.js +388 -0
- package/dist/io.d.ts +78 -0
- package/dist/io.js +379 -0
- package/dist/lzma-formats.d.ts +75 -0
- package/dist/lzma-formats.js +373 -0
- package/dist/lzma-sniff.d.ts +20 -0
- package/dist/lzma-sniff.js +73 -0
- package/dist/lzma-writers.d.ts +35 -0
- package/dist/lzma-writers.js +276 -0
- package/dist/lzma1/LICENSE +201 -0
- package/dist/lzma1/NOTICE +36 -0
- package/dist/lzma1/crc32.d.ts +4 -0
- package/dist/lzma1/crc32.js +19 -0
- package/dist/lzma1/hash234.d.ts +22 -0
- package/dist/lzma1/hash234.js +75 -0
- package/dist/lzma1/hc4.d.ts +30 -0
- package/dist/lzma1/hc4.js +142 -0
- package/dist/lzma1/header.d.ts +32 -0
- package/dist/lzma1/header.js +73 -0
- package/dist/lzma1/lz-decoder.d.ts +41 -0
- package/dist/lzma1/lz-decoder.js +128 -0
- package/dist/lzma1/lz-encoder.d.ts +87 -0
- package/dist/lzma1/lz-encoder.js +166 -0
- package/dist/lzma1/lzma-coder.d.ts +107 -0
- package/dist/lzma1/lzma-coder.js +162 -0
- package/dist/lzma1/lzma-decoder.d.ts +36 -0
- package/dist/lzma1/lzma-decoder.js +484 -0
- package/dist/lzma1/lzma-encoder-fast.d.ts +13 -0
- package/dist/lzma1/lzma-encoder-fast.js +114 -0
- package/dist/lzma1/lzma-encoder.d.ts +105 -0
- package/dist/lzma1/lzma-encoder.js +497 -0
- package/dist/lzma1/lzma2-decoder.d.ts +85 -0
- package/dist/lzma1/lzma2-decoder.js +249 -0
- package/dist/lzma1/range-coder.d.ts +18 -0
- package/dist/lzma1/range-coder.js +23 -0
- package/dist/lzma1/range-decoder.d.ts +41 -0
- package/dist/lzma1/range-decoder.js +78 -0
- package/dist/lzma1/range-encoder.d.ts +53 -0
- package/dist/lzma1/range-encoder.js +269 -0
- package/dist/lzma1-stream.d.ts +60 -0
- package/dist/lzma1-stream.js +202 -0
- package/dist/model.d.ts +141 -0
- package/dist/model.js +16 -0
- package/dist/names.d.ts +13 -0
- package/dist/names.js +66 -0
- package/dist/pack.d.ts +72 -0
- package/dist/pack.js +514 -0
- package/dist/plugins.d.ts +13 -0
- package/dist/plugins.js +55 -0
- package/dist/rules.d.ts +25 -0
- package/dist/rules.js +403 -0
- package/dist/score.d.ts +17 -0
- package/dist/score.js +58 -0
- package/dist/seven.d.ts +75 -0
- package/dist/seven.js +492 -0
- package/dist/sevenzip.d.ts +133 -0
- package/dist/sevenzip.js +529 -0
- package/dist/single.d.ts +103 -0
- package/dist/single.js +453 -0
- package/dist/sniff.d.ts +20 -0
- package/dist/sniff.js +224 -0
- package/dist/stream-meter.d.ts +39 -0
- package/dist/stream-meter.js +54 -0
- package/dist/tar.d.ts +102 -0
- package/dist/tar.js +765 -0
- package/dist/types.d.ts +284 -0
- package/dist/types.js +133 -0
- package/dist/unpack.d.ts +67 -0
- package/dist/unpack.js +194 -0
- package/dist/xz.d.ts +25 -0
- package/dist/xz.js +333 -0
- package/dist/zip-lzma.d.ts +15 -0
- package/dist/zip-lzma.js +137 -0
- package/dist/zip-writer.d.ts +41 -0
- package/dist/zip-writer.js +263 -0
- package/dist/zip.d.ts +99 -0
- package/dist/zip.js +901 -0
- package/dist/zipcrypt.d.ts +47 -0
- package/dist/zipcrypt.js +233 -0
- package/dist/zstd.d.ts +25 -0
- package/dist/zstd.js +160 -0
- package/package.json +94 -4
package/dist/findings.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FindingFactory = void 0;
|
|
4
|
+
exports.findingSpec = findingSpec;
|
|
5
|
+
exports.allFindingSpecs = allFindingSpecs;
|
|
6
|
+
// The finding table and the factory, as pdf-defuse src/findings.ts has them, with archive-defuse's own kinds.
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
const specs = new Map();
|
|
9
|
+
function def(c, d, action, weight, description) {
|
|
10
|
+
specs.set(`${c}/${d}`, { action, weight, description });
|
|
11
|
+
}
|
|
12
|
+
// CORRUPTED
|
|
13
|
+
def(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.Unparseable, 'reject', 0, 'Archive cannot be parsed<: {reason}|>');
|
|
14
|
+
def(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.Truncated, 'reject', 0, 'Archive ends before its last <{what}|entry>');
|
|
15
|
+
def(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.DataError, 'reject', 0, 'The compressed data does not decode<: {reason}|>');
|
|
16
|
+
def(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.EntryData, 'strip', 30, 'Entry removed because its data does not decode or does not match its size or checksum<: {reason}|>');
|
|
17
|
+
def(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.CheckFailed, 'reject', 0, 'An integrity check does not match<: {check}|>');
|
|
18
|
+
// STRUCTURE
|
|
19
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.LeadingBytes, 'strip', 10, 'Data before the start of the archive');
|
|
20
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.TrailingBytes, 'strip', 10, 'Data after the end of the archive');
|
|
21
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.HiddenData, 'strip', 20, 'Data inside the archive that belongs to no entry');
|
|
22
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.Polyglot, 'strip', 40, 'The file also reads as <{type}|another format>');
|
|
23
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.SeveralEndRecords, 'strip', 30, 'More than one end of central directory record, which readers can pick differently');
|
|
24
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.HeaderMismatch, 'strip', 40, 'Two headers of the archive disagree<: {what}|>');
|
|
25
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.OffsetShift, 'strip', 20, 'The offsets in the central directory are shifted, which some readers correct and others do not');
|
|
26
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.Overlap, 'strip', 50, 'Entries share bytes of the archive');
|
|
27
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.ExtraField, 'strip', 0, 'An entry carries <{field}|header data> that the rewrite does not keep');
|
|
28
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.NonFileData, 'strip', 10, 'An entry that is not a file carries data');
|
|
29
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.MultipleStreams, 'strip', 10, 'The file holds <count> compressed streams one after another, and some readers stop after the first');
|
|
30
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.MalformedHeader, 'strip', 10, 'A header is malformed<: {reason}|>');
|
|
31
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.MultiVolume, 'reject', 0, 'The archive is one part of a set split across several files');
|
|
32
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.StreamPadding, 'info', 0, 'Stream padding between or after xz streams');
|
|
33
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.BadPadding, 'strip', 20, 'Padding of a length or content the xz format does not allow');
|
|
34
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.IndexMismatch, 'strip', 30, 'The xz index disagrees with the blocks it lists<: {reason}|>');
|
|
35
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.SizeMismatch, 'strip', 20, 'A declared size disagrees with the data<: {reason}|>');
|
|
36
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.NoCheck, 'info', 0, 'The xz stream carries no integrity check, so the decoded data was not verified');
|
|
37
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.UnknownCheck, 'strip', 10, 'An xz integrity check of a type this package does not know, so the decoded data was not verified');
|
|
38
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.UnknownProperty, 'strip', 5, 'A 7z header property this package does not use<: {property}|>');
|
|
39
|
+
def(types_1.ArchiveCategory.Structure, types_1.ArchiveDetail.EmptyStartHeader, 'strip', 10, 'The 7z start header is empty, as an archive whose writing did not finish leaves it. The header was found at the end of the file, where 7-Zip looks for it');
|
|
40
|
+
// NAME
|
|
41
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Traversal, 'strip', 70, 'An entry name climbs out of the folder it is extracted to');
|
|
42
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Absolute, 'strip', 60, 'An entry name is an absolute path');
|
|
43
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.DriveLetter, 'strip', 60, 'An entry name starts with a drive letter');
|
|
44
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Backslash, 'strip', 20, 'An entry name holds a backslash, which Windows reads as a folder separator');
|
|
45
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.EmptySegment, 'strip', 5, 'An entry name has empty or "." parts');
|
|
46
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.ControlCharacter, 'strip', 40, 'An entry name holds control characters or characters that reorder text');
|
|
47
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.WindowsReserved, 'strip', 20, 'An entry name is one Windows cannot create as written');
|
|
48
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Encoding, 'strip', 5, 'An entry name has no single reading in the encodings readers use');
|
|
49
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.UnicodePath, 'strip', 30, 'The Unicode path field of an entry names a different file than its header');
|
|
50
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Empty, 'strip', 10, 'An entry has an empty name');
|
|
51
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.TooLong, 'info', 10, 'An entry name is longer than file systems allow');
|
|
52
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.Duplicate, 'strip', 40, 'Several entries have the same name, and readers keep different ones');
|
|
53
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.CaseCollision, 'strip', 20, 'Entry names differ only in case, so they collide on file systems that ignore case');
|
|
54
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.NormalizationCollision, 'strip', 30, 'Entry names differ only in Unicode normalization, so they collide on file systems that normalize names');
|
|
55
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.FileDirectoryClash, 'strip', 30, 'An entry is a file or a link where other entries need a folder');
|
|
56
|
+
def(types_1.ArchiveCategory.Name, types_1.ArchiveDetail.ShortNameCollision, 'strip', 30, 'An entry name has the form of a Windows 8.3 short name that another name in its folder could get');
|
|
57
|
+
// LINK
|
|
58
|
+
def(types_1.ArchiveCategory.Link, types_1.ArchiveDetail.Symlink, 'info', 10, 'A symbolic link');
|
|
59
|
+
def(types_1.ArchiveCategory.Link, types_1.ArchiveDetail.Hardlink, 'info', 10, 'A hard link');
|
|
60
|
+
def(types_1.ArchiveCategory.Link, types_1.ArchiveDetail.Outside, 'strip', 70, 'A link points outside the folder the archive is extracted to');
|
|
61
|
+
def(types_1.ArchiveCategory.Link, types_1.ArchiveDetail.Dangling, 'strip', 40, 'A hard link names no entry before it, so extraction links to whatever file has that name');
|
|
62
|
+
def(types_1.ArchiveCategory.Link, types_1.ArchiveDetail.ThroughLink, 'strip', 70, 'An entry is written through a symbolic link of the archive');
|
|
63
|
+
// SPECIAL
|
|
64
|
+
def(types_1.ArchiveCategory.Special, types_1.ArchiveDetail.Device, 'strip', 60, 'A device file');
|
|
65
|
+
def(types_1.ArchiveCategory.Special, types_1.ArchiveDetail.Fifo, 'strip', 30, 'A named pipe');
|
|
66
|
+
def(types_1.ArchiveCategory.Special, types_1.ArchiveDetail.Socket, 'strip', 30, 'A socket');
|
|
67
|
+
def(types_1.ArchiveCategory.Special, types_1.ArchiveDetail.UnknownType, 'strip', 20, 'An entry of a type this package does not recognize');
|
|
68
|
+
def(types_1.ArchiveCategory.Special, types_1.ArchiveDetail.AntiItem, 'strip', 20, 'An entry is a 7z anti-item, which tells an updater to delete a file');
|
|
69
|
+
// PERMISSIONS
|
|
70
|
+
def(types_1.ArchiveCategory.Permissions, types_1.ArchiveDetail.Setuid, 'strip', 50, 'An entry has the setuid bit, which runs it as its owner');
|
|
71
|
+
def(types_1.ArchiveCategory.Permissions, types_1.ArchiveDetail.Setgid, 'strip', 40, "An entry has the setgid bit, which runs it as its group or gives a folder's group to new files");
|
|
72
|
+
def(types_1.ArchiveCategory.Permissions, types_1.ArchiveDetail.Sticky, 'strip', 10, 'An entry has the sticky bit');
|
|
73
|
+
def(types_1.ArchiveCategory.Permissions, types_1.ArchiveDetail.Capability, 'strip', 60, 'An entry carries file capabilities, which grant privileges when it runs');
|
|
74
|
+
// ENCRYPTED
|
|
75
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.ZipCrypto, 'info', 0, "Entry encrypted with PKWARE's traditional encryption");
|
|
76
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Aes128, 'info', 0, 'Entry encrypted with AES and a 128-bit key');
|
|
77
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Aes192, 'info', 0, 'Entry encrypted with AES and a 192-bit key');
|
|
78
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Aes256, 'info', 0, 'Entry encrypted with AES and a 256-bit key');
|
|
79
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Decrypted, 'strip', 0, 'Entry decrypted with a supplied password');
|
|
80
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.EmptyPassword, 'strip', 10, 'Entry encrypted with an empty password');
|
|
81
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.PasswordRequired, 'reject', 0, 'An entry requires a password, and none supplied opened it');
|
|
82
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Unsupported, 'reject', 0, 'An entry uses encryption this package cannot open<: {reason}|>');
|
|
83
|
+
def(types_1.ArchiveCategory.Encrypted, types_1.ArchiveDetail.Header, 'strip', 0, 'The 7z header, which holds the names, was decrypted with a supplied password. The output does not encrypt it');
|
|
84
|
+
// COMPRESSION
|
|
85
|
+
def(types_1.ArchiveCategory.Compression, types_1.ArchiveDetail.UnsupportedMethod, 'reject', 0, 'An entry uses a compression method this package cannot decode<: {method}|>');
|
|
86
|
+
def(types_1.ArchiveCategory.Compression, types_1.ArchiveDetail.UnusualMethod, 'info', 10, 'An entry uses a compression method few readers handle<: {method}|>');
|
|
87
|
+
def(types_1.ArchiveCategory.Compression, types_1.ArchiveDetail.Unavailable, 'reject', 0, 'The data uses <{method}|a compression method> that this Node does not provide');
|
|
88
|
+
def(types_1.ArchiveCategory.Compression, types_1.ArchiveDetail.UnsupportedFeature, 'reject', 0, 'The file uses a feature this package cannot read<: {reason}|>');
|
|
89
|
+
// ENTRY
|
|
90
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.NoPlugin, 'strip', 30, '<Entry "{name}"|An entry> (<{sniffed}|unknown type>) removed. No plugin accepts this type');
|
|
91
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.TypeMismatch, 'info', 40, 'The types of <entry "{name}"|an unnamed entry> disagree: <its name says {nameType}|its name has no known extension>, and <its content looks like {sniffed}|its content is not recognized>');
|
|
92
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.PluginPassed, 'info', 20, 'Entry kept by plugin <plugin> with nothing removed');
|
|
93
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.PluginScrubbed, 'info', 10, 'Entry cleaned and kept by plugin <plugin>');
|
|
94
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.PluginFailed, 'strip', 0, 'Plugin <plugin> failed, so the entry was removed');
|
|
95
|
+
def(types_1.ArchiveCategory.Entry, types_1.ArchiveDetail.PluginRemoved, 'strip', 0, 'Entry removed by plugin <plugin>');
|
|
96
|
+
// METADATA
|
|
97
|
+
def(types_1.ArchiveCategory.Metadata, types_1.ArchiveDetail.Comment, 'info', 0, 'The archive or an entry carries a comment');
|
|
98
|
+
def(types_1.ArchiveCategory.Metadata, types_1.ArchiveDetail.Stripped, 'info', 0, 'Metadata removed because the caller turned on metadata stripping');
|
|
99
|
+
// LIMIT
|
|
100
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.FileSize, 'reject', 0, 'Archive exceeds the file size limit');
|
|
101
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.EntryCount, 'reject', 0, 'Archive exceeds the entry count limit');
|
|
102
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.DecompressedSize, 'reject', 0, 'An entry exceeds the decompressed size limit');
|
|
103
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.TotalDecompressedSize, 'reject', 0, 'The entries together exceed the total decompressed size limit');
|
|
104
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.Ratio, 'reject', 0, 'An entry exceeds the compression ratio limit');
|
|
105
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.DictionarySize, 'reject', 0, 'Decoding needs more dictionary memory than the dictionary size limit allows');
|
|
106
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.NestingDepth, 'reject', 0, 'Archive exceeds the nesting depth limit');
|
|
107
|
+
def(types_1.ArchiveCategory.Limit, types_1.ArchiveDetail.Time, 'reject', 0, 'Archive exceeds the time limit');
|
|
108
|
+
// PROCESSING
|
|
109
|
+
def(types_1.ArchiveCategory.Processing, types_1.ArchiveDetail.MemoryFallback, 'info', 0, '<part> was too large for memory and went through a temporary file');
|
|
110
|
+
def(types_1.ArchiveCategory.Processing, types_1.ArchiveDetail.VerificationFailed, 'reject', 0, 'The defused output did not pass its own inspection, so nothing was written');
|
|
111
|
+
def(types_1.ArchiveCategory.Processing, types_1.ArchiveDetail.ContentRemoved, 'strip', 20, 'Content was removed that no other finding names');
|
|
112
|
+
/** The built-in spec for a kind of finding, or undefined for a kind archive-defuse does not make, such as one from another package. */
|
|
113
|
+
function findingSpec(category, detail) {
|
|
114
|
+
return specs.get(`${category}/${detail}`);
|
|
115
|
+
}
|
|
116
|
+
/** The spec of a kind archive-defuse makes itself, which always has one. */
|
|
117
|
+
function ownSpec(category, detail) {
|
|
118
|
+
const s = findingSpec(category, detail);
|
|
119
|
+
if (!s)
|
|
120
|
+
throw new Error(`No finding spec for ${category}/${detail}`);
|
|
121
|
+
return s;
|
|
122
|
+
}
|
|
123
|
+
function allFindingSpecs() {
|
|
124
|
+
return [...specs.entries()].map(([k, s]) => {
|
|
125
|
+
const [category, detail] = k.split('/');
|
|
126
|
+
return { category, detail, ...s };
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
class FindingFactory {
|
|
130
|
+
overrides;
|
|
131
|
+
constructor(overrides = []) {
|
|
132
|
+
this.overrides = overrides;
|
|
133
|
+
}
|
|
134
|
+
actionFor(category, detail) {
|
|
135
|
+
const exact = this.overrides.find(o => o.category === category && o.detail === detail);
|
|
136
|
+
if (exact)
|
|
137
|
+
return exact.action;
|
|
138
|
+
const byCategory = this.overrides.find(o => o.category === category && o.detail === undefined);
|
|
139
|
+
if (byCategory)
|
|
140
|
+
return byCategory.action;
|
|
141
|
+
return ownSpec(category, detail).action;
|
|
142
|
+
}
|
|
143
|
+
/** True when findings of this kind remove what they report. */
|
|
144
|
+
strips(category, detail) {
|
|
145
|
+
return this.actionFor(category, detail) === 'strip';
|
|
146
|
+
}
|
|
147
|
+
make(category, detail, location, data) {
|
|
148
|
+
const spec = ownSpec(category, detail);
|
|
149
|
+
// Values can come from the archive, so the description shows no control or direction characters from them.
|
|
150
|
+
const shown = (v) => String(v).replace(/[\p{Cc}\p{Cf}]/gu, '?');
|
|
151
|
+
const description = spec.description.replace(/<([^<>]*)>/g, (m, body) => {
|
|
152
|
+
if (/^[a-z]+$/.test(body))
|
|
153
|
+
return data?.[body] !== undefined ? shown(data[body]) : m;
|
|
154
|
+
for (const alt of body.split('|')) {
|
|
155
|
+
let missing = false;
|
|
156
|
+
const filled = alt.replace(/\{([a-zA-Z]+)\}/g, (_, key) => {
|
|
157
|
+
const v = data?.[key];
|
|
158
|
+
if (v === undefined || v === '')
|
|
159
|
+
missing = true;
|
|
160
|
+
const s = shown(v ?? '');
|
|
161
|
+
return s.length > 60 ? `${s.slice(0, 57)}...` : s;
|
|
162
|
+
});
|
|
163
|
+
if (!missing)
|
|
164
|
+
return filled;
|
|
165
|
+
}
|
|
166
|
+
return m;
|
|
167
|
+
});
|
|
168
|
+
const f = { category, detail, description, action: this.actionFor(category, detail) };
|
|
169
|
+
if (location !== undefined)
|
|
170
|
+
f.location = location;
|
|
171
|
+
if (data !== undefined && Object.keys(data).length)
|
|
172
|
+
f.data = data;
|
|
173
|
+
return f;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.FindingFactory = FindingFactory;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TempDir } from './io';
|
|
2
|
+
import type { Archive, Entry } from './model';
|
|
3
|
+
import type { Limits } from './stream-meter';
|
|
4
|
+
import { type ArchiveFormat, type ByteSource } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* The format the content has, from its first bytes. A file that starts with no signature of ours can still be a ZIP
|
|
7
|
+
* archive with data in front, which its end record shows, or Brotli, which has no signature and is tried last.
|
|
8
|
+
*/
|
|
9
|
+
export declare function detect(source: ByteSource): Promise<ArchiveFormat | undefined>;
|
|
10
|
+
/** Opens the archive in the format `detect` found. A file in no format of ours throws the UNPARSEABLE refusal. */
|
|
11
|
+
export declare function openArchive(source: ByteSource, limits: Limits, deadline: number | undefined, passwords: string[], temp?: {
|
|
12
|
+
dir: TempDir;
|
|
13
|
+
threshold: number;
|
|
14
|
+
}): Promise<Archive<Entry>>;
|
package/dist/formats.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detect = detect;
|
|
4
|
+
exports.openArchive = openArchive;
|
|
5
|
+
const cab_1 = require("./cab");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
const lzma_formats_1 = require("./lzma-formats");
|
|
8
|
+
const lzma_sniff_1 = require("./lzma-sniff");
|
|
9
|
+
const single_1 = require("./single");
|
|
10
|
+
const tar_1 = require("./tar");
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
const zip_1 = require("./zip");
|
|
13
|
+
const zstd_1 = require("./zstd");
|
|
14
|
+
const isZipStart = (b) => b.length >= 4 && b[0] === 0x50 && b[1] === 0x4b && ((b[2] === 3 && b[3] === 4) || (b[2] === 5 && b[3] === 6) || (b[2] === 7 && b[3] === 8));
|
|
15
|
+
const startsWith = (b, bytes) => b.length >= bytes.length && bytes.every((x, i) => b[i] === x);
|
|
16
|
+
/** Formats with a signature that no package of the family reads. */
|
|
17
|
+
function otherFormat(b) {
|
|
18
|
+
const s = Buffer.from(b.subarray(0, 8)).toString('latin1');
|
|
19
|
+
if (s.startsWith('Rar!\x1a\x07'))
|
|
20
|
+
return 'RAR';
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The format the content has, from its first bytes. A file that starts with no signature of ours can still be a ZIP
|
|
25
|
+
* archive with data in front, which its end record shows, or Brotli, which has no signature and is tried last.
|
|
26
|
+
*/
|
|
27
|
+
async function detect(source) {
|
|
28
|
+
const size = await source.size();
|
|
29
|
+
const head = await source.read(0, Math.min(1024, size));
|
|
30
|
+
if (isZipStart(head))
|
|
31
|
+
return 'zip';
|
|
32
|
+
if (startsWith(head, lzma_sniff_1.XZ_MAGIC))
|
|
33
|
+
return 'xz';
|
|
34
|
+
if (startsWith(head, lzma_sniff_1.SEVENZIP_MAGIC))
|
|
35
|
+
return '7z';
|
|
36
|
+
if ((0, single_1.isGzip)(head))
|
|
37
|
+
return 'gzip';
|
|
38
|
+
if ((0, single_1.isBzip2)(head))
|
|
39
|
+
return 'bzip2';
|
|
40
|
+
if ((0, zstd_1.isZstdMagic)(head))
|
|
41
|
+
return 'zstd';
|
|
42
|
+
if ((0, cab_1.isCab)(head))
|
|
43
|
+
return 'cab';
|
|
44
|
+
if ((0, tar_1.isTar)(head))
|
|
45
|
+
return 'tar';
|
|
46
|
+
// An archive with no entries is its two end blocks, and a tar writer pads it with more zeros.
|
|
47
|
+
if (size >= 1024 && size % 512 === 0 && head.every(b => b === 0))
|
|
48
|
+
return 'tar';
|
|
49
|
+
if (otherFormat(head) !== undefined)
|
|
50
|
+
return undefined;
|
|
51
|
+
// An .lzma header has no magic, and 14 zero bytes pass liblzma's own test, so a ZIP found from its end comes first.
|
|
52
|
+
if (await (0, zip_1.hasZipEnd)(source))
|
|
53
|
+
return 'zip';
|
|
54
|
+
if ((0, lzma_sniff_1.looksLikeLzma)(head))
|
|
55
|
+
return 'lzma';
|
|
56
|
+
// A 7z archive after other data, such as the program of a self-extracting archive.
|
|
57
|
+
if ((0, lzma_sniff_1.detectLzmaFormat)(await source.read(0, Math.min(size, lzma_sniff_1.SEVENZIP_SEARCH)))?.format === '7z')
|
|
58
|
+
return '7z';
|
|
59
|
+
if (await (0, single_1.looksLikeBrotli)(source))
|
|
60
|
+
return 'brotli';
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/** Opens the archive in the format `detect` found. A file in no format of ours throws the UNPARSEABLE refusal. */
|
|
64
|
+
async function openArchive(source, limits, deadline, passwords, temp) {
|
|
65
|
+
const format = await detect(source);
|
|
66
|
+
switch (format) {
|
|
67
|
+
case 'zip': {
|
|
68
|
+
const zip = await zip_1.ZipArchive.open(source, limits, deadline);
|
|
69
|
+
if (temp)
|
|
70
|
+
zip.decoders = { temp: temp.dir, threshold: temp.threshold, limits };
|
|
71
|
+
return zip;
|
|
72
|
+
}
|
|
73
|
+
case 'tar':
|
|
74
|
+
return tar_1.TarArchive.open(source, limits, deadline);
|
|
75
|
+
case 'gzip':
|
|
76
|
+
return single_1.GzipArchive.open(source);
|
|
77
|
+
case 'bzip2':
|
|
78
|
+
return single_1.Bzip2Archive.open(source);
|
|
79
|
+
case 'zstd':
|
|
80
|
+
return single_1.ZstdArchive.open(source, deadline);
|
|
81
|
+
case 'brotli':
|
|
82
|
+
return single_1.BrotliArchive.open(source);
|
|
83
|
+
case 'cab':
|
|
84
|
+
return cab_1.CabArchive.open(source, limits, deadline);
|
|
85
|
+
case '7z':
|
|
86
|
+
return lzma_formats_1.SevenZipArchive.open(source, limits, deadline, passwords);
|
|
87
|
+
case 'xz':
|
|
88
|
+
return lzma_formats_1.XzArchive.open(source, limits);
|
|
89
|
+
case 'lzma':
|
|
90
|
+
return lzma_formats_1.LzmaArchive.open(source, limits);
|
|
91
|
+
default: {
|
|
92
|
+
const other = otherFormat(await source.read(0, 8));
|
|
93
|
+
const reason = other ? `a ${other} file, which this package does not read` : 'not an archive this package reads';
|
|
94
|
+
throw new errors_1.StopError(types_1.ArchiveCategory.Corrupted, types_1.ArchiveDetail.Unparseable, reason, { reason });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { disarmArchive, disarmArchiveSource, inspectArchive, inspectArchiveSource } from './engine';
|
|
2
|
+
export { allFindingSpecs } from './findings';
|
|
3
|
+
export { bufferSink, bufferSource, fileSink, fileSource, writableSink } from './io';
|
|
4
|
+
export { type CompressFormat, compress, compressStream, compressTo, createArchive, createArchiveBytes, createArchiveStream, type PackData, type PackEntry, PackError, type PackFormat, type PackOptions, } from './pack';
|
|
5
|
+
export { archivePlugin, passThrough } from './plugins';
|
|
6
|
+
export { COMBINATIONS, DEFAULT_BANDS, scoreFindings } from './score';
|
|
7
|
+
export * from './types';
|
|
8
|
+
export { ArchiveReadError, type ArchiveReader, type ArchiveReaderEntry, decompress, type OpenArchiveOptions, openArchive } from './unpack';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.openArchive = exports.decompress = exports.ArchiveReadError = exports.scoreFindings = exports.DEFAULT_BANDS = exports.COMBINATIONS = exports.passThrough = exports.archivePlugin = exports.PackError = exports.createArchiveStream = exports.createArchiveBytes = exports.createArchive = exports.compressTo = exports.compressStream = exports.compress = exports.writableSink = exports.fileSource = exports.fileSink = exports.bufferSource = exports.bufferSink = exports.allFindingSpecs = exports.inspectArchiveSource = exports.inspectArchive = exports.disarmArchiveSource = exports.disarmArchive = void 0;
|
|
18
|
+
var engine_1 = require("./engine");
|
|
19
|
+
Object.defineProperty(exports, "disarmArchive", { enumerable: true, get: function () { return engine_1.disarmArchive; } });
|
|
20
|
+
Object.defineProperty(exports, "disarmArchiveSource", { enumerable: true, get: function () { return engine_1.disarmArchiveSource; } });
|
|
21
|
+
Object.defineProperty(exports, "inspectArchive", { enumerable: true, get: function () { return engine_1.inspectArchive; } });
|
|
22
|
+
Object.defineProperty(exports, "inspectArchiveSource", { enumerable: true, get: function () { return engine_1.inspectArchiveSource; } });
|
|
23
|
+
var findings_1 = require("./findings");
|
|
24
|
+
Object.defineProperty(exports, "allFindingSpecs", { enumerable: true, get: function () { return findings_1.allFindingSpecs; } });
|
|
25
|
+
var io_1 = require("./io");
|
|
26
|
+
Object.defineProperty(exports, "bufferSink", { enumerable: true, get: function () { return io_1.bufferSink; } });
|
|
27
|
+
Object.defineProperty(exports, "bufferSource", { enumerable: true, get: function () { return io_1.bufferSource; } });
|
|
28
|
+
Object.defineProperty(exports, "fileSink", { enumerable: true, get: function () { return io_1.fileSink; } });
|
|
29
|
+
Object.defineProperty(exports, "fileSource", { enumerable: true, get: function () { return io_1.fileSource; } });
|
|
30
|
+
Object.defineProperty(exports, "writableSink", { enumerable: true, get: function () { return io_1.writableSink; } });
|
|
31
|
+
var pack_1 = require("./pack");
|
|
32
|
+
Object.defineProperty(exports, "compress", { enumerable: true, get: function () { return pack_1.compress; } });
|
|
33
|
+
Object.defineProperty(exports, "compressStream", { enumerable: true, get: function () { return pack_1.compressStream; } });
|
|
34
|
+
Object.defineProperty(exports, "compressTo", { enumerable: true, get: function () { return pack_1.compressTo; } });
|
|
35
|
+
Object.defineProperty(exports, "createArchive", { enumerable: true, get: function () { return pack_1.createArchive; } });
|
|
36
|
+
Object.defineProperty(exports, "createArchiveBytes", { enumerable: true, get: function () { return pack_1.createArchiveBytes; } });
|
|
37
|
+
Object.defineProperty(exports, "createArchiveStream", { enumerable: true, get: function () { return pack_1.createArchiveStream; } });
|
|
38
|
+
Object.defineProperty(exports, "PackError", { enumerable: true, get: function () { return pack_1.PackError; } });
|
|
39
|
+
var plugins_1 = require("./plugins");
|
|
40
|
+
Object.defineProperty(exports, "archivePlugin", { enumerable: true, get: function () { return plugins_1.archivePlugin; } });
|
|
41
|
+
Object.defineProperty(exports, "passThrough", { enumerable: true, get: function () { return plugins_1.passThrough; } });
|
|
42
|
+
var score_1 = require("./score");
|
|
43
|
+
Object.defineProperty(exports, "COMBINATIONS", { enumerable: true, get: function () { return score_1.COMBINATIONS; } });
|
|
44
|
+
Object.defineProperty(exports, "DEFAULT_BANDS", { enumerable: true, get: function () { return score_1.DEFAULT_BANDS; } });
|
|
45
|
+
Object.defineProperty(exports, "scoreFindings", { enumerable: true, get: function () { return score_1.scoreFindings; } });
|
|
46
|
+
__exportStar(require("./types"), exports);
|
|
47
|
+
var unpack_1 = require("./unpack");
|
|
48
|
+
Object.defineProperty(exports, "ArchiveReadError", { enumerable: true, get: function () { return unpack_1.ArchiveReadError; } });
|
|
49
|
+
Object.defineProperty(exports, "decompress", { enumerable: true, get: function () { return unpack_1.decompress; } });
|
|
50
|
+
Object.defineProperty(exports, "openArchive", { enumerable: true, get: function () { return unpack_1.openArchive; } });
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import cjs from './index.js';
|
|
2
|
+
export const { disarmArchive, disarmArchiveSource, inspectArchive, inspectArchiveSource, allFindingSpecs, bufferSink, bufferSource, fileSink, fileSource, writableSink, compress, compressStream, compressTo, createArchive, createArchiveBytes, createArchiveStream, PackError, archivePlugin, passThrough, COMBINATIONS, DEFAULT_BANDS, scoreFindings, ArchiveReadError, decompress, openArchive, ArchiveCategory, ArchiveDetail, ArchiveRisk } = cjs;
|
|
3
|
+
export default cjs;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Consumed } from './codecs';
|
|
2
|
+
/**
|
|
3
|
+
* Decodes a raw Deflate64 stream. Stops after the final block; consumed.bytes then counts the input bytes the stream
|
|
4
|
+
* used, so bytes after it are the caller's. Output comes in chunks of at most 64 KiB.
|
|
5
|
+
*/
|
|
6
|
+
export declare function inflate64(chunks: AsyncIterable<Uint8Array>, consumed?: Consumed, deadline?: number): AsyncGenerator<Uint8Array>;
|