@stigmer/zip-structure 3.13.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 +190 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -0
- package/index.js +2 -0
- package/index.js.map +1 -0
- package/package.json +36 -0
- package/src/__tests__/zip-structure.test.ts +124 -0
- package/src/index.ts +6 -0
- package/src/testing.ts +205 -0
- package/src/zip-structure.ts +248 -0
- package/testing.d.ts +65 -0
- package/testing.d.ts.map +1 -0
- package/testing.js +132 -0
- package/testing.js.map +1 -0
- package/zip-structure.d.ts +99 -0
- package/zip-structure.d.ts.map +1 -0
- package/zip-structure.js +169 -0
- package/zip-structure.js.map +1 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy-free structural ZIP parsing: end-of-central-directory (EOCD)
|
|
3
|
+
* location plus central-directory walk, producing one record per entry.
|
|
4
|
+
*
|
|
5
|
+
* Lived in the runner (src/shared/zip-structure.ts) until the TS server's
|
|
6
|
+
* skill push gate became its second consumer; extracted to backend/libs/ts/
|
|
7
|
+
* per the program's shared-library rule (a library moves here when a second
|
|
8
|
+
* consumer exists — @stigmer/temporal-codecs is the precedent).
|
|
9
|
+
*
|
|
10
|
+
* Parsing is *central-directory-based* — never a front-to-back walk of
|
|
11
|
+
* local file headers. This is a correctness decision, not a style choice
|
|
12
|
+
* (issues #450 and #567): local headers of streaming entries
|
|
13
|
+
* (general-purpose flag bit 3) carry zeroed sizes, and the only
|
|
14
|
+
* local-only way to recover them is scanning the payload for the
|
|
15
|
+
* data-descriptor signature — which silently truncates any stored entry
|
|
16
|
+
* whose *content* happens to contain those four bytes, and
|
|
17
|
+
* desynchronizes every entry after it. The central directory always
|
|
18
|
+
* carries the real sizes, and every consumer here holds the complete
|
|
19
|
+
* archive bytes, so nothing a local-header walk could offer is needed.
|
|
20
|
+
*
|
|
21
|
+
* This layer maps bytes to entry records and nothing else. Policy — what
|
|
22
|
+
* a structural failure means, which entries are acceptable, how payloads
|
|
23
|
+
* are decoded — belongs to the consumers, and they differ on purpose:
|
|
24
|
+
*
|
|
25
|
+
* - runner shared/zip-extract.ts (skill artifacts): structural failure
|
|
26
|
+
* is NON-FATAL — both editions' push gates validated every artifact
|
|
27
|
+
* with a central-directory-based reader before storage, so a defect
|
|
28
|
+
* here can only be a truncated or corrupted download.
|
|
29
|
+
* - runner execute-deep-agent/attachment-injector.ts (user
|
|
30
|
+
* attachments): structural failure is FAIL-HARD — the input is an
|
|
31
|
+
* untrusted upload and nothing upstream vouched for it.
|
|
32
|
+
* - stigmer-server src/domain/skill/storage/ (the push gate):
|
|
33
|
+
* FAIL-HARD, plus a safearchive-parity entry pre-filter decoded from
|
|
34
|
+
* the raw creator/attribute fields exposed below.
|
|
35
|
+
*
|
|
36
|
+
* ZIP64 is deliberately unsupported: every consumer caps input far below
|
|
37
|
+
* every ZIP64 threshold (skill push gates: 100MB / 10,000 files;
|
|
38
|
+
* attachment uploads: 10MB).
|
|
39
|
+
*
|
|
40
|
+
* Throws plain `Error`s on structural defects (no valid EOCD, a central
|
|
41
|
+
* directory or local header record that does not parse, a payload slice
|
|
42
|
+
* that runs past the end of the buffer); consumers translate those into
|
|
43
|
+
* their own error models.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
// ─── Entry records ───────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
export interface ZipStructuralEntry {
|
|
49
|
+
/** Entry path exactly as recorded in the central directory. */
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly isDirectory: boolean;
|
|
52
|
+
readonly compressionMethod: number;
|
|
53
|
+
/**
|
|
54
|
+
* The central directory's declared uncompressed size — authoritative for
|
|
55
|
+
* pre-extraction accounting (e.g. ZIP-bomb budgeting), but still a
|
|
56
|
+
* *declaration*: a consumer that distrusts its input must enforce it
|
|
57
|
+
* against the actual decompressed output.
|
|
58
|
+
*/
|
|
59
|
+
readonly uncompressedSize: number;
|
|
60
|
+
/** The central directory's declared compressed size (the payload length). */
|
|
61
|
+
readonly compressedSize: number;
|
|
62
|
+
/**
|
|
63
|
+
* The central directory's CRC-32 of the uncompressed content, verbatim.
|
|
64
|
+
* Raw fact for consumers that verify payload integrity after
|
|
65
|
+
* decompression (Go's archive/zip checks it on every read); consumers
|
|
66
|
+
* that trust their input ignore it.
|
|
67
|
+
*/
|
|
68
|
+
readonly crc32: number;
|
|
69
|
+
/**
|
|
70
|
+
* The central directory's "version made by" field, verbatim. The high
|
|
71
|
+
* byte identifies the creator OS (0 = MS-DOS/FAT, 3 = Unix, 19 = macOS),
|
|
72
|
+
* which decides how `externalAttributes` is interpreted. Raw facts for
|
|
73
|
+
* policy layers that decode entry file modes; most consumers ignore it.
|
|
74
|
+
*/
|
|
75
|
+
readonly versionMadeBy: number;
|
|
76
|
+
/**
|
|
77
|
+
* The central directory's external file attributes field, verbatim.
|
|
78
|
+
* Unix creators store the POSIX mode in the high 16 bits; MS-DOS
|
|
79
|
+
* creators store FAT attribute bits in the low byte. Interpretation is
|
|
80
|
+
* policy — see the server's safearchive-parity pre-filter.
|
|
81
|
+
*/
|
|
82
|
+
readonly externalAttributes: number;
|
|
83
|
+
/** The entry's raw payload slice (a view, not a copy) of the archive buffer. */
|
|
84
|
+
readonly compressedData: Uint8Array;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ─── Format constants ────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
const LOCAL_FILE_HEADER_SIG = 0x04034b50;
|
|
90
|
+
const CENTRAL_DIRECTORY_SIG = 0x02014b50;
|
|
91
|
+
const EOCD_SIG = 0x06054b50;
|
|
92
|
+
|
|
93
|
+
/** Fixed size of the EOCD record, excluding the variable-length comment. */
|
|
94
|
+
export const EOCD_MIN_SIZE = 22;
|
|
95
|
+
/** The archive comment length is a u16, so the EOCD sits within the last 64KB + 22 bytes. */
|
|
96
|
+
const EOCD_MAX_COMMENT = 0xffff;
|
|
97
|
+
|
|
98
|
+
const LOCAL_HEADER_SIZE = 30;
|
|
99
|
+
const CD_RECORD_SIZE = 46;
|
|
100
|
+
|
|
101
|
+
// ─── Parsing ─────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Enumerate the archive's entries from its central directory.
|
|
105
|
+
*
|
|
106
|
+
* Throws on any structural defect: no valid EOCD, a central directory or
|
|
107
|
+
* local header record that doesn't parse, or a payload slice that runs
|
|
108
|
+
* past the end of the buffer.
|
|
109
|
+
*/
|
|
110
|
+
export function parseZipStructure(data: Uint8Array): ZipStructuralEntry[] {
|
|
111
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
112
|
+
const eocd = findEndOfCentralDirectory(data, view);
|
|
113
|
+
|
|
114
|
+
const entries: ZipStructuralEntry[] = [];
|
|
115
|
+
let offset = eocd.centralDirectoryOffset;
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < eocd.entryCount; i++) {
|
|
118
|
+
if (offset + CD_RECORD_SIZE > data.length || view.getUint32(offset, true) !== CENTRAL_DIRECTORY_SIG) {
|
|
119
|
+
throw new Error(`invalid central directory record at offset ${offset}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const versionMadeBy = view.getUint16(offset + 4, true);
|
|
123
|
+
const compressionMethod = view.getUint16(offset + 10, true);
|
|
124
|
+
const crc32 = view.getUint32(offset + 16, true);
|
|
125
|
+
const compressedSize = view.getUint32(offset + 20, true);
|
|
126
|
+
const uncompressedSize = view.getUint32(offset + 24, true);
|
|
127
|
+
const fileNameLength = view.getUint16(offset + 28, true);
|
|
128
|
+
const extraFieldLength = view.getUint16(offset + 30, true);
|
|
129
|
+
const commentLength = view.getUint16(offset + 32, true);
|
|
130
|
+
const externalAttributes = view.getUint32(offset + 38, true);
|
|
131
|
+
const localHeaderOffset = view.getUint32(offset + 42, true);
|
|
132
|
+
|
|
133
|
+
const fileName = new TextDecoder().decode(
|
|
134
|
+
data.subarray(offset + CD_RECORD_SIZE, offset + CD_RECORD_SIZE + fileNameLength),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// The local header is consulted for one thing only: the payload start.
|
|
138
|
+
// Its name/extra field lengths can legitimately differ from the central
|
|
139
|
+
// directory's (streaming writers pad the extra field), so the offset
|
|
140
|
+
// cannot be derived from CD fields alone.
|
|
141
|
+
const dataStart = payloadStart(data, view, localHeaderOffset, fileName);
|
|
142
|
+
if (dataStart + compressedSize > data.length) {
|
|
143
|
+
throw new Error(`entry "${fileName}" payload runs past end of archive`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
entries.push({
|
|
147
|
+
name: fileName,
|
|
148
|
+
isDirectory: fileName.endsWith("/"),
|
|
149
|
+
compressionMethod,
|
|
150
|
+
uncompressedSize,
|
|
151
|
+
compressedSize,
|
|
152
|
+
crc32,
|
|
153
|
+
versionMadeBy,
|
|
154
|
+
externalAttributes,
|
|
155
|
+
compressedData: data.subarray(dataStart, dataStart + compressedSize),
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
offset += CD_RECORD_SIZE + fileNameLength + extraFieldLength + commentLength;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return entries;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface EndOfCentralDirectory {
|
|
165
|
+
centralDirectoryOffset: number;
|
|
166
|
+
entryCount: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Locate and validate the end-of-central-directory record.
|
|
171
|
+
*
|
|
172
|
+
* Scans backward from the end of the archive across the maximum comment
|
|
173
|
+
* span. A signature match alone is not trusted (the four bytes can occur
|
|
174
|
+
* inside a trailing comment): the record must also point at an offset
|
|
175
|
+
* that actually holds a central directory record, or be a genuinely
|
|
176
|
+
* empty archive.
|
|
177
|
+
*/
|
|
178
|
+
function findEndOfCentralDirectory(data: Uint8Array, view: DataView): EndOfCentralDirectory {
|
|
179
|
+
const scanFloor = Math.max(0, data.length - EOCD_MIN_SIZE - EOCD_MAX_COMMENT);
|
|
180
|
+
|
|
181
|
+
for (let pos = data.length - EOCD_MIN_SIZE; pos >= scanFloor; pos--) {
|
|
182
|
+
if (view.getUint32(pos, true) !== EOCD_SIG) continue;
|
|
183
|
+
|
|
184
|
+
const entryCount = view.getUint16(pos + 10, true);
|
|
185
|
+
const centralDirectorySize = view.getUint32(pos + 12, true);
|
|
186
|
+
const centralDirectoryOffset = view.getUint32(pos + 16, true);
|
|
187
|
+
|
|
188
|
+
const directoryEndsAtRecord = centralDirectoryOffset + centralDirectorySize <= pos;
|
|
189
|
+
const directoryLooksReal =
|
|
190
|
+
entryCount === 0 ||
|
|
191
|
+
(centralDirectoryOffset + 4 <= data.length &&
|
|
192
|
+
view.getUint32(centralDirectoryOffset, true) === CENTRAL_DIRECTORY_SIG);
|
|
193
|
+
|
|
194
|
+
if (directoryEndsAtRecord && directoryLooksReal) {
|
|
195
|
+
return { centralDirectoryOffset, entryCount };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
throw new Error("no end-of-central-directory record found");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ─── CRC-32 ──────────────────────────────────────────────────────────────
|
|
203
|
+
|
|
204
|
+
// Standard CRC-32 (IEEE 802.3, the ZIP checksum), table-driven so callers
|
|
205
|
+
// hashing payloads at the consumers' 100 MB caps stay cheap.
|
|
206
|
+
const CRC_TABLE = (() => {
|
|
207
|
+
const table = new Uint32Array(256);
|
|
208
|
+
for (let n = 0; n < 256; n++) {
|
|
209
|
+
let c = n;
|
|
210
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
211
|
+
c = (c >>> 1) ^ (0xedb88320 & -(c & 1));
|
|
212
|
+
}
|
|
213
|
+
table[n] = c;
|
|
214
|
+
}
|
|
215
|
+
return table;
|
|
216
|
+
})();
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* CRC-32 of `data` — the ZIP checksum. Exported for consumers that verify
|
|
220
|
+
* decompressed payloads against an entry's declared `crc32` (Go's
|
|
221
|
+
* archive/zip does this on every read) and for the fixture builder.
|
|
222
|
+
*/
|
|
223
|
+
export function crc32(data: Uint8Array): number {
|
|
224
|
+
let crc = 0xffffffff;
|
|
225
|
+
for (let i = 0; i < data.length; i++) {
|
|
226
|
+
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ data[i]!) & 0xff]!;
|
|
227
|
+
}
|
|
228
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Resolve where an entry's payload begins, from its local file header. */
|
|
232
|
+
function payloadStart(
|
|
233
|
+
data: Uint8Array,
|
|
234
|
+
view: DataView,
|
|
235
|
+
localHeaderOffset: number,
|
|
236
|
+
fileName: string,
|
|
237
|
+
): number {
|
|
238
|
+
if (
|
|
239
|
+
localHeaderOffset + LOCAL_HEADER_SIZE > data.length ||
|
|
240
|
+
view.getUint32(localHeaderOffset, true) !== LOCAL_FILE_HEADER_SIG
|
|
241
|
+
) {
|
|
242
|
+
throw new Error(`entry "${fileName}" has no local file header at offset ${localHeaderOffset}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const localNameLength = view.getUint16(localHeaderOffset + 26, true);
|
|
246
|
+
const localExtraLength = view.getUint16(localHeaderOffset + 28, true);
|
|
247
|
+
return localHeaderOffset + LOCAL_HEADER_SIZE + localNameLength + localExtraLength;
|
|
248
|
+
}
|
package/testing.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-level ZIP fixture builder for the structural parser's consumers'
|
|
3
|
+
* tests (exported as `@stigmer/zip-structure/testing`). Moved here from the
|
|
4
|
+
* runner's src/__test-utils__/zip-fixtures.ts when the lib was extracted —
|
|
5
|
+
* the lib's own tests, the runner's, and the TS server's skill-gate tests
|
|
6
|
+
* all craft archives with it, and one builder keeps their fixture shapes
|
|
7
|
+
* from drifting apart.
|
|
8
|
+
*
|
|
9
|
+
* Emits complete, real-shaped archives — local file headers (optionally
|
|
10
|
+
* streaming-style, the Go stdlib writer's default), payloads, central
|
|
11
|
+
* directory, and EOCD — because that is the only shape that can reach the
|
|
12
|
+
* runner: both editions' skill push gates validate artifacts with
|
|
13
|
+
* central-directory-based readers (see zip-structure.ts's module doc).
|
|
14
|
+
* Earlier fixtures emitted local headers only, a shape no real ZIP writer
|
|
15
|
+
* produces, and were coupled to the old parser's front-to-back walk.
|
|
16
|
+
*
|
|
17
|
+
* Mirrors the conformance suite's `zipFilesStreaming()`
|
|
18
|
+
* (test/conformance/src/support/skills.ts) so unit fixtures and
|
|
19
|
+
* cross-edition fixtures share one shape.
|
|
20
|
+
*/
|
|
21
|
+
export interface ZipFixtureFile {
|
|
22
|
+
name: string;
|
|
23
|
+
/** Text content is UTF-8 encoded; pass bytes directly for binary payloads. */
|
|
24
|
+
content: string | Uint8Array;
|
|
25
|
+
/** Compression method for the entry. Defaults to stored. */
|
|
26
|
+
method?: "stored" | "deflated";
|
|
27
|
+
/**
|
|
28
|
+
* Emit the entry the way Go's archive/zip does by default: general-purpose
|
|
29
|
+
* flag bit 3 set, zeroed sizes in the local header, and a trailing data
|
|
30
|
+
* descriptor (with the conventional signature) carrying the real values.
|
|
31
|
+
*/
|
|
32
|
+
streaming?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Lie about the entry's uncompressed size everywhere the writer would
|
|
35
|
+
* declare it (local header, data descriptor, central directory). Models a
|
|
36
|
+
* crafted archive whose declarations disagree with its actual payload —
|
|
37
|
+
* the input class the attachment injector's declared-size enforcement
|
|
38
|
+
* exists to reject (issue #567).
|
|
39
|
+
*/
|
|
40
|
+
declaredUncompressedSize?: number;
|
|
41
|
+
/**
|
|
42
|
+
* The central directory's "version made by" field. Defaults to 20
|
|
43
|
+
* (MS-DOS creator, the historical fixture value). Set the high byte to
|
|
44
|
+
* 3 (`0x0300 | 20`) to model a Unix creator, which makes readers
|
|
45
|
+
* interpret `externalAttributes`' high 16 bits as a POSIX mode — how
|
|
46
|
+
* symlink and device entries are represented (the server's
|
|
47
|
+
* safearchive-parity pre-filter fixtures need this).
|
|
48
|
+
*/
|
|
49
|
+
versionMadeBy?: number;
|
|
50
|
+
/** The central directory's external file attributes field. Defaults to 0. */
|
|
51
|
+
externalAttributes?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ZipFixtureOptions {
|
|
54
|
+
/** Trailing archive comment appended after the EOCD record. */
|
|
55
|
+
comment?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Drop the central directory and EOCD, leaving only local headers and
|
|
58
|
+
* payloads. No real ZIP writer produces this shape — it models a download
|
|
59
|
+
* truncated before the archive's index.
|
|
60
|
+
*/
|
|
61
|
+
omitCentralDirectory?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** Build a ZIP archive from path + content pairs. */
|
|
64
|
+
export declare function buildZip(files: ZipFixtureFile[], options?: ZipFixtureOptions): Uint8Array;
|
|
65
|
+
//# sourceMappingURL=testing.d.ts.map
|
package/testing.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC/B;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,qDAAqD;AACrD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CA+FzF"}
|
package/testing.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-level ZIP fixture builder for the structural parser's consumers'
|
|
3
|
+
* tests (exported as `@stigmer/zip-structure/testing`). Moved here from the
|
|
4
|
+
* runner's src/__test-utils__/zip-fixtures.ts when the lib was extracted —
|
|
5
|
+
* the lib's own tests, the runner's, and the TS server's skill-gate tests
|
|
6
|
+
* all craft archives with it, and one builder keeps their fixture shapes
|
|
7
|
+
* from drifting apart.
|
|
8
|
+
*
|
|
9
|
+
* Emits complete, real-shaped archives — local file headers (optionally
|
|
10
|
+
* streaming-style, the Go stdlib writer's default), payloads, central
|
|
11
|
+
* directory, and EOCD — because that is the only shape that can reach the
|
|
12
|
+
* runner: both editions' skill push gates validate artifacts with
|
|
13
|
+
* central-directory-based readers (see zip-structure.ts's module doc).
|
|
14
|
+
* Earlier fixtures emitted local headers only, a shape no real ZIP writer
|
|
15
|
+
* produces, and were coupled to the old parser's front-to-back walk.
|
|
16
|
+
*
|
|
17
|
+
* Mirrors the conformance suite's `zipFilesStreaming()`
|
|
18
|
+
* (test/conformance/src/support/skills.ts) so unit fixtures and
|
|
19
|
+
* cross-edition fixtures share one shape.
|
|
20
|
+
*/
|
|
21
|
+
import { deflateRawSync } from "node:zlib";
|
|
22
|
+
import { crc32 } from "./zip-structure.js";
|
|
23
|
+
/** Build a ZIP archive from path + content pairs. */
|
|
24
|
+
export function buildZip(files, options) {
|
|
25
|
+
const out = new ByteWriter();
|
|
26
|
+
const written = [];
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const contentBytes = typeof file.content === "string" ? new TextEncoder().encode(file.content) : file.content;
|
|
29
|
+
const deflated = file.method === "deflated";
|
|
30
|
+
const payload = deflated ? new Uint8Array(deflateRawSync(contentBytes)) : contentBytes;
|
|
31
|
+
const entry = {
|
|
32
|
+
nameBytes: new TextEncoder().encode(file.name),
|
|
33
|
+
payload,
|
|
34
|
+
declaredUncompressed: file.declaredUncompressedSize ?? contentBytes.length,
|
|
35
|
+
crc: crc32(contentBytes),
|
|
36
|
+
flags: file.streaming ? 0x0008 : 0,
|
|
37
|
+
method: deflated ? 8 : 0,
|
|
38
|
+
versionMadeBy: file.versionMadeBy ?? 20,
|
|
39
|
+
externalAttributes: file.externalAttributes ?? 0,
|
|
40
|
+
localHeaderOffset: out.length,
|
|
41
|
+
};
|
|
42
|
+
written.push(entry);
|
|
43
|
+
out.u32(0x04034b50); // local file header signature
|
|
44
|
+
out.u16(20); // version needed to extract
|
|
45
|
+
out.u16(entry.flags);
|
|
46
|
+
out.u16(entry.method);
|
|
47
|
+
out.u16(0); // mod time
|
|
48
|
+
out.u16(0); // mod date
|
|
49
|
+
out.u32(file.streaming ? 0 : entry.crc);
|
|
50
|
+
out.u32(file.streaming ? 0 : payload.length);
|
|
51
|
+
out.u32(file.streaming ? 0 : entry.declaredUncompressed);
|
|
52
|
+
out.u16(entry.nameBytes.length);
|
|
53
|
+
out.u16(0); // extra field length
|
|
54
|
+
out.raw(entry.nameBytes);
|
|
55
|
+
out.raw(payload);
|
|
56
|
+
if (file.streaming) {
|
|
57
|
+
out.u32(0x08074b50); // data descriptor signature (Go writes it)
|
|
58
|
+
out.u32(entry.crc);
|
|
59
|
+
out.u32(payload.length);
|
|
60
|
+
out.u32(entry.declaredUncompressed);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (options?.omitCentralDirectory) {
|
|
64
|
+
return out.toUint8Array();
|
|
65
|
+
}
|
|
66
|
+
const centralDirectoryOffset = out.length;
|
|
67
|
+
for (const entry of written) {
|
|
68
|
+
out.u32(0x02014b50); // central directory record signature
|
|
69
|
+
out.u16(entry.versionMadeBy);
|
|
70
|
+
out.u16(20); // version needed to extract
|
|
71
|
+
out.u16(entry.flags);
|
|
72
|
+
out.u16(entry.method);
|
|
73
|
+
out.u16(0); // mod time
|
|
74
|
+
out.u16(0); // mod date
|
|
75
|
+
out.u32(entry.crc);
|
|
76
|
+
out.u32(entry.payload.length);
|
|
77
|
+
out.u32(entry.declaredUncompressed);
|
|
78
|
+
out.u16(entry.nameBytes.length);
|
|
79
|
+
out.u16(0); // extra field length
|
|
80
|
+
out.u16(0); // comment length
|
|
81
|
+
out.u16(0); // disk number start
|
|
82
|
+
out.u16(0); // internal attributes
|
|
83
|
+
out.u32(entry.externalAttributes);
|
|
84
|
+
out.u32(entry.localHeaderOffset);
|
|
85
|
+
out.raw(entry.nameBytes);
|
|
86
|
+
}
|
|
87
|
+
const centralDirectorySize = out.length - centralDirectoryOffset;
|
|
88
|
+
const commentBytes = new TextEncoder().encode(options?.comment ?? "");
|
|
89
|
+
out.u32(0x06054b50); // EOCD signature
|
|
90
|
+
out.u16(0); // disk number
|
|
91
|
+
out.u16(0); // disk with central directory
|
|
92
|
+
out.u16(written.length); // entries on this disk
|
|
93
|
+
out.u16(written.length); // total entries
|
|
94
|
+
out.u32(centralDirectorySize);
|
|
95
|
+
out.u32(centralDirectoryOffset);
|
|
96
|
+
out.u16(commentBytes.length);
|
|
97
|
+
out.raw(commentBytes);
|
|
98
|
+
return out.toUint8Array();
|
|
99
|
+
}
|
|
100
|
+
// Chunked assembly instead of a number[]-per-byte accumulator: fixtures at
|
|
101
|
+
// the injector's 100 MB zip-bomb limit are built from payload-sized chunks,
|
|
102
|
+
// which a per-byte spread-push cannot survive (argument-count overflow).
|
|
103
|
+
class ByteWriter {
|
|
104
|
+
chunks = [];
|
|
105
|
+
size = 0;
|
|
106
|
+
get length() {
|
|
107
|
+
return this.size;
|
|
108
|
+
}
|
|
109
|
+
u16(v) {
|
|
110
|
+
this.raw(new Uint8Array([v & 0xff, (v >>> 8) & 0xff]));
|
|
111
|
+
}
|
|
112
|
+
u32(v) {
|
|
113
|
+
this.raw(new Uint8Array([v & 0xff, (v >>> 8) & 0xff, (v >>> 16) & 0xff, (v >>> 24) & 0xff]));
|
|
114
|
+
}
|
|
115
|
+
raw(b) {
|
|
116
|
+
this.chunks.push(b);
|
|
117
|
+
this.size += b.length;
|
|
118
|
+
}
|
|
119
|
+
toUint8Array() {
|
|
120
|
+
const result = new Uint8Array(this.size);
|
|
121
|
+
let offset = 0;
|
|
122
|
+
for (const chunk of this.chunks) {
|
|
123
|
+
result.set(chunk, offset);
|
|
124
|
+
offset += chunk.length;
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// CRC-32 comes from the structural module (one implementation for the
|
|
130
|
+
// parser's consumers and this builder; semantically identical to the
|
|
131
|
+
// conformance suite's inline bit-loop helper).
|
|
132
|
+
//# sourceMappingURL=testing.js.map
|
package/testing.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy-free structural ZIP parsing: end-of-central-directory (EOCD)
|
|
3
|
+
* location plus central-directory walk, producing one record per entry.
|
|
4
|
+
*
|
|
5
|
+
* Lived in the runner (src/shared/zip-structure.ts) until the TS server's
|
|
6
|
+
* skill push gate became its second consumer; extracted to backend/libs/ts/
|
|
7
|
+
* per the program's shared-library rule (a library moves here when a second
|
|
8
|
+
* consumer exists — @stigmer/temporal-codecs is the precedent).
|
|
9
|
+
*
|
|
10
|
+
* Parsing is *central-directory-based* — never a front-to-back walk of
|
|
11
|
+
* local file headers. This is a correctness decision, not a style choice
|
|
12
|
+
* (issues #450 and #567): local headers of streaming entries
|
|
13
|
+
* (general-purpose flag bit 3) carry zeroed sizes, and the only
|
|
14
|
+
* local-only way to recover them is scanning the payload for the
|
|
15
|
+
* data-descriptor signature — which silently truncates any stored entry
|
|
16
|
+
* whose *content* happens to contain those four bytes, and
|
|
17
|
+
* desynchronizes every entry after it. The central directory always
|
|
18
|
+
* carries the real sizes, and every consumer here holds the complete
|
|
19
|
+
* archive bytes, so nothing a local-header walk could offer is needed.
|
|
20
|
+
*
|
|
21
|
+
* This layer maps bytes to entry records and nothing else. Policy — what
|
|
22
|
+
* a structural failure means, which entries are acceptable, how payloads
|
|
23
|
+
* are decoded — belongs to the consumers, and they differ on purpose:
|
|
24
|
+
*
|
|
25
|
+
* - runner shared/zip-extract.ts (skill artifacts): structural failure
|
|
26
|
+
* is NON-FATAL — both editions' push gates validated every artifact
|
|
27
|
+
* with a central-directory-based reader before storage, so a defect
|
|
28
|
+
* here can only be a truncated or corrupted download.
|
|
29
|
+
* - runner execute-deep-agent/attachment-injector.ts (user
|
|
30
|
+
* attachments): structural failure is FAIL-HARD — the input is an
|
|
31
|
+
* untrusted upload and nothing upstream vouched for it.
|
|
32
|
+
* - stigmer-server src/domain/skill/storage/ (the push gate):
|
|
33
|
+
* FAIL-HARD, plus a safearchive-parity entry pre-filter decoded from
|
|
34
|
+
* the raw creator/attribute fields exposed below.
|
|
35
|
+
*
|
|
36
|
+
* ZIP64 is deliberately unsupported: every consumer caps input far below
|
|
37
|
+
* every ZIP64 threshold (skill push gates: 100MB / 10,000 files;
|
|
38
|
+
* attachment uploads: 10MB).
|
|
39
|
+
*
|
|
40
|
+
* Throws plain `Error`s on structural defects (no valid EOCD, a central
|
|
41
|
+
* directory or local header record that does not parse, a payload slice
|
|
42
|
+
* that runs past the end of the buffer); consumers translate those into
|
|
43
|
+
* their own error models.
|
|
44
|
+
*/
|
|
45
|
+
export interface ZipStructuralEntry {
|
|
46
|
+
/** Entry path exactly as recorded in the central directory. */
|
|
47
|
+
readonly name: string;
|
|
48
|
+
readonly isDirectory: boolean;
|
|
49
|
+
readonly compressionMethod: number;
|
|
50
|
+
/**
|
|
51
|
+
* The central directory's declared uncompressed size — authoritative for
|
|
52
|
+
* pre-extraction accounting (e.g. ZIP-bomb budgeting), but still a
|
|
53
|
+
* *declaration*: a consumer that distrusts its input must enforce it
|
|
54
|
+
* against the actual decompressed output.
|
|
55
|
+
*/
|
|
56
|
+
readonly uncompressedSize: number;
|
|
57
|
+
/** The central directory's declared compressed size (the payload length). */
|
|
58
|
+
readonly compressedSize: number;
|
|
59
|
+
/**
|
|
60
|
+
* The central directory's CRC-32 of the uncompressed content, verbatim.
|
|
61
|
+
* Raw fact for consumers that verify payload integrity after
|
|
62
|
+
* decompression (Go's archive/zip checks it on every read); consumers
|
|
63
|
+
* that trust their input ignore it.
|
|
64
|
+
*/
|
|
65
|
+
readonly crc32: number;
|
|
66
|
+
/**
|
|
67
|
+
* The central directory's "version made by" field, verbatim. The high
|
|
68
|
+
* byte identifies the creator OS (0 = MS-DOS/FAT, 3 = Unix, 19 = macOS),
|
|
69
|
+
* which decides how `externalAttributes` is interpreted. Raw facts for
|
|
70
|
+
* policy layers that decode entry file modes; most consumers ignore it.
|
|
71
|
+
*/
|
|
72
|
+
readonly versionMadeBy: number;
|
|
73
|
+
/**
|
|
74
|
+
* The central directory's external file attributes field, verbatim.
|
|
75
|
+
* Unix creators store the POSIX mode in the high 16 bits; MS-DOS
|
|
76
|
+
* creators store FAT attribute bits in the low byte. Interpretation is
|
|
77
|
+
* policy — see the server's safearchive-parity pre-filter.
|
|
78
|
+
*/
|
|
79
|
+
readonly externalAttributes: number;
|
|
80
|
+
/** The entry's raw payload slice (a view, not a copy) of the archive buffer. */
|
|
81
|
+
readonly compressedData: Uint8Array;
|
|
82
|
+
}
|
|
83
|
+
/** Fixed size of the EOCD record, excluding the variable-length comment. */
|
|
84
|
+
export declare const EOCD_MIN_SIZE = 22;
|
|
85
|
+
/**
|
|
86
|
+
* Enumerate the archive's entries from its central directory.
|
|
87
|
+
*
|
|
88
|
+
* Throws on any structural defect: no valid EOCD, a central directory or
|
|
89
|
+
* local header record that doesn't parse, or a payload slice that runs
|
|
90
|
+
* past the end of the buffer.
|
|
91
|
+
*/
|
|
92
|
+
export declare function parseZipStructure(data: Uint8Array): ZipStructuralEntry[];
|
|
93
|
+
/**
|
|
94
|
+
* CRC-32 of `data` — the ZIP checksum. Exported for consumers that verify
|
|
95
|
+
* decompressed payloads against an entry's declared `crc32` (Go's
|
|
96
|
+
* archive/zip does this on every read) and for the fixture builder.
|
|
97
|
+
*/
|
|
98
|
+
export declare function crc32(data: Uint8Array): number;
|
|
99
|
+
//# sourceMappingURL=zip-structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip-structure.d.ts","sourceRoot":"","sources":["../src/zip-structure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC;CACrC;AAQD,4EAA4E;AAC5E,eAAO,MAAM,aAAa,KAAK,CAAC;AAShC;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,kBAAkB,EAAE,CAoDxE;AAwDD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAM9C"}
|