fileport-gateway 0.1.7 → 0.2.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/README.md CHANGED
@@ -14,7 +14,8 @@ Implemented:
14
14
  - reverse proxy with GET/HEAD/Range;
15
15
  - traversal, encoded-path and symlink-escape protection;
16
16
  - CLI and browser preview shell;
17
- - explicit RO/RW shares, expiry and strict existing-file-only atomic saves.
17
+ - explicit RO/RW shares, expiry and strict existing-file-only atomic saves;
18
+ - in-browser archive browsing and bounded entry preview for ZIP and compressed tar files.
18
19
 
19
20
  See [current architecture](docs/CURRENT_ARCHITECTURE,md), [Dufs compatibility](docs/DUFS_COMPATIBILITY,md), and [migration plan](docs/MIGRATION_PLAN,md), and [network/CLI contract](docs/NETWORK_AND_CLI.md).
20
21
 
@@ -58,6 +59,22 @@ fileport share ./report.md --readonly
58
59
 
59
60
  Proxy mode treats `public.url` as the externally advertised URL. DNS is reported for diagnostics but is not required to resolve to a local interface, and the public port does not need to equal the origin listener port. Fileport does not configure or verify the reverse proxy itself; verify the resulting capability URL end to end.
60
61
 
62
+ ## Archive browsing
63
+
64
+ The preview shell recognizes these formats by filename extension:
65
+
66
+ - ZIP: `.zip`
67
+ - tar: `.tar`
68
+ - gzip-compressed tar: `.tar.gz`, `.tgz`
69
+ - bzip2-compressed tar: `.tar.bz2`, `.tbz`, `.tbz2`
70
+ - xz-compressed tar: `.tar.xz`, `.txz`
71
+
72
+ Opening one of these files shows a sorted archive manifest with entry paths, types, uncompressed sizes and ZIP encryption status. Entries marked previewable—supported, unencrypted regular files of at most 10 MiB—can be opened with magic-validated image, PDF or media previews, sanitized Markdown/source/text views, and bounded binary-entry download behavior; a selected binary entry can be downloaded from that view. The original archive remains available through Download. Archive entries are read-only even when the enclosing share is RW.
73
+
74
+ Fileport streams archive parsing and decompression and never extracts archive contents to disk. A selected entry is buffered in memory only after its size has passed the preview checks. Limits are a 512 MiB archive input file, 10,000 entries per archive, 4 KiB per entry path, 4 MiB of aggregate manifest path text, 256 MiB of expanded data per tar scan, and 10 MiB per entry preview. Archive work runs in memory-limited worker threads with bounded global/per-archive concurrency and a 15-second wall-clock timeout. Tar archives are rescanned when an entry is opened; the limit applies to every such scan.
75
+
76
+ Unsafe archive paths are omitted from the manifest and counted. Leading `./` prefixes and trailing directory slashes are normalized; after that, absolute paths, drive-prefixed paths, backslashes, NULs, empty components, and `.` or `..` components are unsafe. Symlinks, hard links and other non-regular entries may be listed but are never followed or previewed. Encrypted ZIP entries and regular files over the preview limit are listed as non-previewable; download the original archive to handle them with a trusted local tool.
77
+
61
78
  ```bash
62
79
  fileport --help
63
80
  fileport share --help
@@ -10,3 +10,23 @@ Fileport Gateway packages the official Linux x86_64 musl binary of [Dufs](https:
10
10
  - Release archive SHA256: `817769f726613194bcff9d0e3e481eaccc86ac11208857614f36a8c02f410977`
11
11
 
12
12
  The corresponding license texts are included in `vendor/LICENSE-DUFS-APACHE` and `vendor/LICENSE-DUFS-MIT`.
13
+
14
+ ## Archive preview dependencies
15
+
16
+ The archive preview implementation uses the following direct runtime dependencies. Versions shown are the versions currently locked by `package-lock.json`.
17
+
18
+ | Package | Purpose | License | Source |
19
+ |---|---|---|---|
20
+ | `yauzl` 3.4.0 | Lazy ZIP directory and entry streaming | MIT | https://github.com/thejoshwolfe/yauzl |
21
+ | `tar-stream` 3.2.1 | Streaming tar parsing | MIT | https://github.com/mafintosh/tar-stream |
22
+ | `unbzip2-stream` 1.4.3 | Streaming bzip2 decompression | MIT | https://github.com/regular/unbzip2-stream |
23
+ | `xz-decompress` 0.2.3 | WebAssembly-backed streaming xz decompression | MIT (package declaration) | https://github.com/httptoolkit/xz-decompress |
24
+ | `mime-types` 3.0.1 | Content types for entry preview responses | MIT | https://github.com/jshttp/mime-types |
25
+
26
+ `xz-decompress` includes the following upstream code, as declared by the notice embedded in its distributed JavaScript bundle:
27
+
28
+ - `xzwasm`, copyright Steve Sanderson, MIT license: https://github.com/SteveSanderson/xzwasm
29
+ - `xz-embedded`, by Lasse Collin and Igor Pavlov, public domain: https://tukaani.org/xz/embedded.html
30
+ - `walloc`, copyright 2020 Igalia, S.L., MIT license: https://github.com/wingo/walloc
31
+
32
+ Gzip decompression is provided by Node.js's built-in `node:zlib` module rather than an additional npm package. Package copyright and license texts are available from the linked upstream repositories and installed package distributions.
@@ -0,0 +1,42 @@
1
+ export declare const MAX_ARCHIVE_ENTRIES = 10000;
2
+ export declare const MAX_ARCHIVE_SCAN_BYTES: number;
3
+ export declare const MAX_ARCHIVE_FILE_BYTES: number;
4
+ export declare const MAX_ARCHIVE_ENTRY_BYTES: number;
5
+ export declare const MAX_ARCHIVE_PATH_BYTES = 4096;
6
+ export declare const MAX_ARCHIVE_MANIFEST_PATH_BYTES: number;
7
+ export type ArchiveFormat = "zip" | "tar" | "tar.gz" | "tar.bz2" | "tar.xz";
8
+ export type ArchiveEntryType = "file" | "directory" | "symlink" | "other";
9
+ export interface ArchiveEntry {
10
+ path: string;
11
+ type: ArchiveEntryType;
12
+ size: number;
13
+ compressedSize?: number;
14
+ modifiedAt?: string;
15
+ previewable: boolean;
16
+ encrypted?: boolean;
17
+ }
18
+ export interface ArchiveManifest {
19
+ format: ArchiveFormat;
20
+ entries: ArchiveEntry[];
21
+ skippedUnsafe: number;
22
+ limits: {
23
+ maxEntries: number;
24
+ maxArchiveBytes: number;
25
+ maxScannedBytes: number;
26
+ maxPreviewBytes: number;
27
+ };
28
+ }
29
+ export interface ArchiveContent {
30
+ entry: ArchiveEntry;
31
+ body: Buffer;
32
+ contentType: string;
33
+ }
34
+ export declare class ArchiveError extends Error {
35
+ readonly status: number;
36
+ readonly code: string;
37
+ constructor(status: number, code: string, message?: string);
38
+ }
39
+ export declare function archiveFormat(file: string): ArchiveFormat | undefined;
40
+ export declare function isArchivePath(file: string): boolean;
41
+ export declare function listArchive(file: string, expectedRealPath?: string): Promise<ArchiveManifest>;
42
+ export declare function readArchiveEntry(file: string, rawEntry: string, expectedRealPath?: string): Promise<ArchiveContent>;
@@ -0,0 +1,372 @@
1
+ import { close as closeFd, constants, createReadStream, fstat, open as openFd } from "node:fs";
2
+ import { realpath } from "node:fs/promises";
3
+ import { createGunzip } from "node:zlib";
4
+ import { createRequire } from "node:module";
5
+ import unbzip2 from "unbzip2-stream";
6
+ import { Readable, Transform } from "node:stream";
7
+ import { pipeline } from "node:stream/promises";
8
+ import { contentType, lookup } from "mime-types";
9
+ import { extract } from "tar-stream";
10
+ import { fromFdPromise } from "yauzl";
11
+ const { XzReadableStream } = createRequire(import.meta.url)("xz-decompress");
12
+ export const MAX_ARCHIVE_ENTRIES = 10_000;
13
+ export const MAX_ARCHIVE_SCAN_BYTES = 256 * 1024 * 1024;
14
+ export const MAX_ARCHIVE_FILE_BYTES = 512 * 1024 * 1024;
15
+ export const MAX_ARCHIVE_ENTRY_BYTES = 10 * 1024 * 1024;
16
+ export const MAX_ARCHIVE_PATH_BYTES = 4096;
17
+ export const MAX_ARCHIVE_MANIFEST_PATH_BYTES = 4 * 1024 * 1024;
18
+ class ArchiveEntryFound extends Error {
19
+ }
20
+ export class ArchiveError extends Error {
21
+ status;
22
+ code;
23
+ constructor(status, code, message = code) {
24
+ super(message);
25
+ this.status = status;
26
+ this.code = code;
27
+ }
28
+ }
29
+ class ByteLimitTransform extends Transform {
30
+ limit;
31
+ seen = 0;
32
+ constructor(limit) {
33
+ super();
34
+ this.limit = limit;
35
+ }
36
+ _transform(chunk, _encoding, callback) {
37
+ this.seen += chunk.length;
38
+ if (this.seen > this.limit)
39
+ return callback(new ArchiveError(413, "archive_scan_too_large", `archive expands beyond the ${this.limit} byte scan limit`));
40
+ callback(null, chunk);
41
+ }
42
+ }
43
+ export function archiveFormat(file) {
44
+ const lower = file.toLowerCase();
45
+ if (lower.endsWith(".zip"))
46
+ return "zip";
47
+ if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz"))
48
+ return "tar.gz";
49
+ if (lower.endsWith(".tar.bz2") || lower.endsWith(".tbz2") || lower.endsWith(".tbz"))
50
+ return "tar.bz2";
51
+ if (lower.endsWith(".tar.xz") || lower.endsWith(".txz"))
52
+ return "tar.xz";
53
+ if (lower.endsWith(".tar"))
54
+ return "tar";
55
+ return undefined;
56
+ }
57
+ export function isArchivePath(file) { return archiveFormat(file) !== undefined; }
58
+ function safeArchivePath(raw) {
59
+ if (!raw || raw.includes("\0") || raw.includes("\\") || raw.startsWith("/") || /^[A-Za-z]:/.test(raw))
60
+ return undefined;
61
+ let value = raw;
62
+ while (value.startsWith("./"))
63
+ value = value.slice(2);
64
+ value = value.replace(/\/+$/, "");
65
+ if (!value || value === ".")
66
+ return undefined;
67
+ const parts = value.split("/");
68
+ if (parts.some(part => !part || part === "." || part === ".."))
69
+ return undefined;
70
+ return parts.join("/");
71
+ }
72
+ function requestedEntryPath(raw) {
73
+ const normalized = safeArchivePath(raw);
74
+ if (!normalized)
75
+ throw new ArchiveError(400, "unsafe_archive_path", "unsafe archive entry path");
76
+ return normalized;
77
+ }
78
+ function limits() { return { maxEntries: MAX_ARCHIVE_ENTRIES, maxArchiveBytes: MAX_ARCHIVE_FILE_BYTES, maxScannedBytes: MAX_ARCHIVE_SCAN_BYTES, maxPreviewBytes: MAX_ARCHIVE_ENTRY_BYTES }; }
79
+ function mimeFor(file, body) {
80
+ const lower = file.toLowerCase(), textual = /\.(?:md|markdown|txt|json|csv|tsv|ya?ml|toml|xml|html?|css|js|mjs|cjs|ts|tsx|jsx|py|go|rs|java|kt|sh|bash|zsh|fish|sql|log|ini|conf)$/i.test(lower);
81
+ if (textual) {
82
+ try {
83
+ new TextDecoder("utf-8", { fatal: true }).decode(body);
84
+ return contentType(lookup(file) || "text/plain") || "text/plain; charset=utf-8";
85
+ }
86
+ catch {
87
+ return "application/octet-stream";
88
+ }
89
+ }
90
+ if (body.length >= 8 && body.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])))
91
+ return "image/png";
92
+ if (body.length >= 3 && body[0] === 0xff && body[1] === 0xd8 && body[2] === 0xff)
93
+ return "image/jpeg";
94
+ if (body.length >= 6 && (body.subarray(0, 6).toString("ascii") === "GIF87a" || body.subarray(0, 6).toString("ascii") === "GIF89a"))
95
+ return "image/gif";
96
+ if (body.length >= 12 && body.subarray(0, 4).toString("ascii") === "RIFF" && body.subarray(8, 12).toString("ascii") === "WEBP")
97
+ return "image/webp";
98
+ if (body.length >= 12 && body.subarray(0, 4).toString("ascii") === "RIFF" && body.subarray(8, 12).toString("ascii") === "WAVE")
99
+ return "audio/wav";
100
+ if (body.length >= 4 && body.subarray(0, 4).toString("ascii") === "OggS")
101
+ return "audio/ogg";
102
+ if (body.length >= 4 && body.subarray(0, 4).toString("ascii") === "fLaC")
103
+ return "audio/flac";
104
+ if (body.length >= 3 && body.subarray(0, 3).toString("ascii") === "ID3" || body.length >= 2 && body[0] === 0xff && (body[1] & 0xe0) === 0xe0)
105
+ return "audio/mpeg";
106
+ if (body.length >= 12 && body.subarray(4, 8).toString("ascii") === "ftyp")
107
+ return "video/mp4";
108
+ if (body.length >= 4 && body[0] === 0x1a && body[1] === 0x45 && body[2] === 0xdf && body[3] === 0xa3)
109
+ return "video/webm";
110
+ if (body.length >= 5 && body.subarray(0, 5).toString("ascii") === "%PDF-")
111
+ return "application/pdf";
112
+ return "application/octet-stream";
113
+ }
114
+ function zipType(entry) {
115
+ if (entry.fileName.endsWith("/"))
116
+ return "directory";
117
+ const unixType = (entry.externalFileAttributes >>> 16) & 0xf000;
118
+ if (unixType === 0xa000)
119
+ return "symlink";
120
+ if (unixType && unixType !== 0x8000)
121
+ return "other";
122
+ return "file";
123
+ }
124
+ function tarType(header) {
125
+ if (header.type === "file" || header.type === "contiguous-file")
126
+ return "file";
127
+ if (header.type === "directory")
128
+ return "directory";
129
+ if (header.type === "link" || header.type === "symlink")
130
+ return "symlink";
131
+ return "other";
132
+ }
133
+ function archiveEntry(path, type, size, modifiedAt, compressedSize, encrypted) {
134
+ return { path, type, size, ...(compressedSize === undefined ? {} : { compressedSize }), ...(modifiedAt ? { modifiedAt } : {}), previewable: type === "file" && !encrypted && size <= MAX_ARCHIVE_ENTRY_BYTES, ...(encrypted ? { encrypted: true } : {}) };
135
+ }
136
+ function stableEntries(entries) { return entries.sort((a, b) => a.path.localeCompare(b.path) || a.type.localeCompare(b.type)); }
137
+ async function openArchiveFile(file, expectedRealPath) {
138
+ let handle;
139
+ try {
140
+ handle = await new Promise((resolve, reject) => openFd(file, constants.O_RDONLY | constants.O_NOFOLLOW, (error, fd) => error ? reject(error) : resolve(fd)));
141
+ }
142
+ catch (error) {
143
+ const code = error.code;
144
+ if (code === "ELOOP")
145
+ throw new ArchiveError(409, "archive_target_changed", "archive target changed during authorization");
146
+ throw error;
147
+ }
148
+ const stat = await new Promise((resolve, reject) => fstat(handle, (error, value) => error ? reject(error) : resolve(value)));
149
+ let actual;
150
+ try {
151
+ actual = await realpath(`/proc/self/fd/${handle}`);
152
+ }
153
+ catch {
154
+ await closeArchiveFile(handle);
155
+ throw new ArchiveError(409, "archive_target_changed", "cannot verify opened archive target");
156
+ }
157
+ if (actual !== expectedRealPath) {
158
+ await closeArchiveFile(handle);
159
+ throw new ArchiveError(409, "archive_target_changed", "archive target changed during authorization");
160
+ }
161
+ if (!stat.isFile()) {
162
+ await closeArchiveFile(handle);
163
+ throw new ArchiveError(415, "archive_not_regular_file");
164
+ }
165
+ if (stat.size > MAX_ARCHIVE_FILE_BYTES) {
166
+ await closeArchiveFile(handle);
167
+ throw new ArchiveError(413, "archive_file_too_large", `archive exceeds the ${MAX_ARCHIVE_FILE_BYTES} byte input limit`);
168
+ }
169
+ return handle;
170
+ }
171
+ async function closeArchiveFile(handle) {
172
+ await new Promise((resolve, reject) => closeFd(handle, error => error && error.code !== "EBADF" ? reject(error) : resolve()));
173
+ }
174
+ async function listZip(file, expectedRealPath) {
175
+ const handle = await openArchiveFile(file, expectedRealPath);
176
+ let zip;
177
+ try {
178
+ zip = await fromFdPromise(handle, { lazyEntries: true, autoClose: false, validateEntrySizes: true, strictFileNames: false });
179
+ }
180
+ catch {
181
+ await closeArchiveFile(handle);
182
+ throw new ArchiveError(422, "invalid_archive", "cannot read ZIP archive");
183
+ }
184
+ if (zip.entryCount > MAX_ARCHIVE_ENTRIES) {
185
+ try {
186
+ zip.close();
187
+ }
188
+ catch { }
189
+ throw new ArchiveError(413, "archive_too_many_entries", `archive contains more than ${MAX_ARCHIVE_ENTRIES} entries`);
190
+ }
191
+ const entries = [];
192
+ let skippedUnsafe = 0, pathBytes = 0;
193
+ try {
194
+ for await (const item of zip.eachEntry()) {
195
+ if (entries.length >= MAX_ARCHIVE_ENTRIES)
196
+ throw new ArchiveError(413, "archive_too_many_entries", `archive contains more than ${MAX_ARCHIVE_ENTRIES} entries`);
197
+ const normalized = safeArchivePath(item.fileName);
198
+ if (!normalized) {
199
+ skippedUnsafe++;
200
+ continue;
201
+ }
202
+ const bytes = Buffer.byteLength(normalized);
203
+ if (bytes > MAX_ARCHIVE_PATH_BYTES)
204
+ throw new ArchiveError(413, "archive_path_too_long");
205
+ pathBytes += bytes;
206
+ if (pathBytes > MAX_ARCHIVE_MANIFEST_PATH_BYTES)
207
+ throw new ArchiveError(413, "archive_manifest_too_large");
208
+ const type = zipType(item), encrypted = item.isEncrypted();
209
+ let modifiedAt;
210
+ try {
211
+ modifiedAt = item.getLastModDate().toISOString();
212
+ }
213
+ catch { }
214
+ const meta = archiveEntry(normalized, type, item.uncompressedSize, modifiedAt, item.compressedSize, encrypted);
215
+ meta.previewable = meta.previewable && item.canDecodeFileData() && item.compressedSize <= MAX_ARCHIVE_SCAN_BYTES;
216
+ entries.push(meta);
217
+ }
218
+ }
219
+ catch (error) {
220
+ if (error instanceof ArchiveError)
221
+ throw error;
222
+ throw new ArchiveError(422, "invalid_archive", "cannot read ZIP archive");
223
+ }
224
+ finally {
225
+ try {
226
+ zip.close();
227
+ }
228
+ catch { }
229
+ }
230
+ return { format: "zip", entries: stableEntries(entries), skippedUnsafe, limits: limits() };
231
+ }
232
+ async function readZipEntry(file, requested, expectedRealPath) {
233
+ const handle = await openArchiveFile(file, expectedRealPath);
234
+ let zip;
235
+ try {
236
+ zip = await fromFdPromise(handle, { lazyEntries: true, autoClose: false, validateEntrySizes: true, strictFileNames: false });
237
+ }
238
+ catch {
239
+ await closeArchiveFile(handle);
240
+ throw new ArchiveError(422, "invalid_archive", "cannot read ZIP archive");
241
+ }
242
+ if (zip.entryCount > MAX_ARCHIVE_ENTRIES) {
243
+ try {
244
+ zip.close();
245
+ }
246
+ catch { }
247
+ throw new ArchiveError(413, "archive_too_many_entries", `archive contains more than ${MAX_ARCHIVE_ENTRIES} entries`);
248
+ }
249
+ try {
250
+ for await (const item of zip.eachEntry()) {
251
+ const normalized = safeArchivePath(item.fileName);
252
+ if (normalized !== requested)
253
+ continue;
254
+ const type = zipType(item), encrypted = item.isEncrypted(), meta = archiveEntry(normalized, type, item.uncompressedSize, undefined, item.compressedSize, encrypted);
255
+ if (type !== "file" || encrypted || !item.canDecodeFileData())
256
+ throw new ArchiveError(415, encrypted ? "archive_entry_encrypted" : "archive_entry_not_previewable");
257
+ if (item.uncompressedSize > MAX_ARCHIVE_ENTRY_BYTES || item.compressedSize > MAX_ARCHIVE_SCAN_BYTES)
258
+ throw new ArchiveError(413, "archive_entry_too_large", `archive entry exceeds the ${MAX_ARCHIVE_ENTRY_BYTES} byte preview limit`);
259
+ const stream = await zip.openReadStreamPromise(item);
260
+ const chunks = [];
261
+ let size = 0;
262
+ for await (const chunk of stream) {
263
+ const value = Buffer.from(chunk);
264
+ size += value.length;
265
+ if (size > MAX_ARCHIVE_ENTRY_BYTES) {
266
+ stream.destroy();
267
+ throw new ArchiveError(413, "archive_entry_too_large");
268
+ }
269
+ chunks.push(value);
270
+ }
271
+ const body = Buffer.concat(chunks);
272
+ return { entry: meta, body, contentType: mimeFor(requested, body) };
273
+ }
274
+ throw new ArchiveError(404, "archive_entry_not_found");
275
+ }
276
+ catch (error) {
277
+ if (error instanceof ArchiveError)
278
+ throw error;
279
+ throw new ArchiveError(422, "invalid_archive", "cannot extract ZIP entry");
280
+ }
281
+ finally {
282
+ try {
283
+ zip.close();
284
+ }
285
+ catch { }
286
+ }
287
+ }
288
+ async function scanTar(file, format, expectedRealPath, requested) {
289
+ const parser = extract();
290
+ const entries = [];
291
+ let seenEntries = 0, skippedUnsafe = 0, pathBytes = 0, content, parserError;
292
+ parser.on("entry", (header, stream, next) => {
293
+ const normalized = safeArchivePath(header.name), type = tarType(header), size = Number(header.size || 0);
294
+ if (!Number.isSafeInteger(size) || size < 0)
295
+ return next(new ArchiveError(422, "invalid_archive", "invalid tar entry size"));
296
+ seenEntries++;
297
+ if (seenEntries > MAX_ARCHIVE_ENTRIES)
298
+ return next(new ArchiveError(413, "archive_too_many_entries", `archive contains more than ${MAX_ARCHIVE_ENTRIES} entries`));
299
+ if (!normalized) {
300
+ skippedUnsafe++;
301
+ stream.on("end", () => next());
302
+ stream.resume();
303
+ return;
304
+ }
305
+ const bytes = Buffer.byteLength(normalized);
306
+ if (bytes > MAX_ARCHIVE_PATH_BYTES)
307
+ return next(new ArchiveError(413, "archive_path_too_long"));
308
+ pathBytes += bytes;
309
+ if (pathBytes > MAX_ARCHIVE_MANIFEST_PATH_BYTES)
310
+ return next(new ArchiveError(413, "archive_manifest_too_large"));
311
+ const modifiedAt = header.mtime instanceof Date && !Number.isNaN(header.mtime.getTime()) ? header.mtime.toISOString() : undefined;
312
+ const meta = archiveEntry(normalized, type, size, modifiedAt);
313
+ entries.push(meta);
314
+ if (requested === normalized) {
315
+ if (type !== "file")
316
+ return next(new ArchiveError(415, "archive_entry_not_previewable"));
317
+ if (size > MAX_ARCHIVE_ENTRY_BYTES)
318
+ return next(new ArchiveError(413, "archive_entry_too_large", `archive entry exceeds the ${MAX_ARCHIVE_ENTRY_BYTES} byte preview limit`));
319
+ const chunks = [];
320
+ let actual = 0;
321
+ stream.on("data", (chunk) => { const value = Buffer.from(chunk); actual += value.length; if (actual <= MAX_ARCHIVE_ENTRY_BYTES)
322
+ chunks.push(value); });
323
+ stream.on("end", () => { if (actual > MAX_ARCHIVE_ENTRY_BYTES)
324
+ return next(new ArchiveError(413, "archive_entry_too_large")); const body = Buffer.concat(chunks); content = { entry: meta, body, contentType: mimeFor(requested, body) }; next(new ArchiveEntryFound()); });
325
+ return;
326
+ }
327
+ stream.on("end", () => next());
328
+ stream.resume();
329
+ });
330
+ parser.on("error", error => { parserError = error; });
331
+ const handle = await openArchiveFile(file, expectedRealPath), source = createReadStream(file, { fd: handle, autoClose: true }), limiter = new ByteLimitTransform(MAX_ARCHIVE_SCAN_BYTES);
332
+ try {
333
+ if (format === "tar.gz")
334
+ await pipeline(source, createGunzip(), limiter, parser);
335
+ else if (format === "tar.bz2")
336
+ await pipeline(source, unbzip2(), limiter, parser);
337
+ else if (format === "tar.xz")
338
+ await pipeline(Readable.fromWeb(new XzReadableStream(Readable.toWeb(source))), limiter, parser);
339
+ else
340
+ await pipeline(source, limiter, parser);
341
+ }
342
+ catch (error) {
343
+ const cause = parserError || error;
344
+ if (cause instanceof ArchiveEntryFound && content)
345
+ return { entries, skippedUnsafe, content };
346
+ if (cause instanceof ArchiveError)
347
+ throw cause;
348
+ throw new ArchiveError(422, "invalid_archive", `cannot read ${format} archive`);
349
+ }
350
+ return { entries: stableEntries(entries), skippedUnsafe, content };
351
+ }
352
+ export async function listArchive(file, expectedRealPath = file) {
353
+ const format = archiveFormat(file);
354
+ if (!format)
355
+ throw new ArchiveError(415, "unsupported_archive", "supported archives: .zip, .tar, .tar.gz, .tgz, .tar.bz2, .tbz2, .tar.xz, .txz");
356
+ if (format === "zip")
357
+ return listZip(file, expectedRealPath);
358
+ const result = await scanTar(file, format, expectedRealPath);
359
+ return { format, entries: result.entries, skippedUnsafe: result.skippedUnsafe, limits: limits() };
360
+ }
361
+ export async function readArchiveEntry(file, rawEntry, expectedRealPath = file) {
362
+ const requested = requestedEntryPath(rawEntry), format = archiveFormat(file);
363
+ if (!format)
364
+ throw new ArchiveError(415, "unsupported_archive");
365
+ if (format === "zip")
366
+ return readZipEntry(file, requested, expectedRealPath);
367
+ const result = await scanTar(file, format, expectedRealPath, requested);
368
+ if (!result.content)
369
+ throw new ArchiveError(404, "archive_entry_not_found");
370
+ return result.content;
371
+ }
372
+ //# sourceMappingURL=archive-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-engine.js","sourceRoot":"","sources":["../src/archive-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import { parentPort, workerData } from "node:worker_threads";
2
+ import { ArchiveError, listArchive, readArchiveEntry } from "./archive-engine.js";
3
+ try {
4
+ const input = workerData;
5
+ const value = input.action === "list" ? await listArchive(input.file, input.expectedRealPath) : await readArchiveEntry(input.file, input.entry ?? "", input.expectedRealPath);
6
+ parentPort.postMessage({ ok: true, value });
7
+ }
8
+ catch (error) {
9
+ const value = error instanceof ArchiveError ? error : new ArchiveError(422, "invalid_archive", error instanceof Error ? error.message : String(error));
10
+ parentPort.postMessage({ ok: false, error: { status: value.status, code: value.code, message: value.message } });
11
+ }
12
+ //# sourceMappingURL=archive-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive-worker.js","sourceRoot":"","sources":["../src/archive-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGlF,IAAG,CAAC;IACF,MAAM,KAAK,GAAC,UAAkB,CAAC;IAC/B,MAAM,KAAK,GAAC,KAAK,CAAC,MAAM,KAAG,MAAM,CAAA,CAAC,CAAA,MAAM,WAAW,CAAC,KAAK,CAAC,IAAI,EAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA,CAAC,CAAA,MAAM,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAC,KAAK,CAAC,KAAK,IAAE,EAAE,EAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACjK,UAAW,CAAC,WAAW,CAAC,EAAC,EAAE,EAAC,IAAI,EAAC,KAAK,EAAC,CAAC,CAAC;AAC3C,CAAC;AAAA,OAAM,KAAK,EAAC,CAAC;IAAA,MAAM,KAAK,GAAC,KAAK,YAAY,YAAY,CAAA,CAAC,CAAA,KAAK,CAAA,CAAC,CAAA,IAAI,YAAY,CAAC,GAAG,EAAC,iBAAiB,EAAC,KAAK,YAAY,KAAK,CAAA,CAAC,CAAA,KAAK,CAAC,OAAO,CAAA,CAAC,CAAA,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAAA,UAAW,CAAC,WAAW,CAAC,EAAC,EAAE,EAAC,KAAK,EAAC,KAAK,EAAC,EAAC,MAAM,EAAC,KAAK,CAAC,MAAM,EAAC,IAAI,EAAC,KAAK,CAAC,IAAI,EAAC,OAAO,EAAC,KAAK,CAAC,OAAO,EAAC,EAAC,CAAC,CAAC;AAAA,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type ArchiveContent, type ArchiveFormat, type ArchiveManifest } from "./archive-engine.js";
2
+ export type { ArchiveContent, ArchiveEntry, ArchiveEntryType, ArchiveFormat, ArchiveManifest } from "./archive-engine.js";
3
+ export { MAX_ARCHIVE_ENTRIES, MAX_ARCHIVE_ENTRY_BYTES, MAX_ARCHIVE_FILE_BYTES, MAX_ARCHIVE_PATH_BYTES, MAX_ARCHIVE_MANIFEST_PATH_BYTES, MAX_ARCHIVE_SCAN_BYTES } from "./archive-engine.js";
4
+ export declare class ArchiveError extends Error {
5
+ readonly status: number;
6
+ readonly code: string;
7
+ constructor(status: number, code: string, message?: string);
8
+ }
9
+ export interface ArchiveJobOptions {
10
+ expectedRealPath: string;
11
+ key: string;
12
+ signal?: AbortSignal;
13
+ }
14
+ export declare function archiveFormat(file: string): ArchiveFormat | undefined;
15
+ export declare function isArchivePath(file: string): boolean;
16
+ export declare function listArchive(file: string, options?: ArchiveJobOptions): Promise<ArchiveManifest>;
17
+ export declare function readArchiveEntry(file: string, rawEntry: string, options?: ArchiveJobOptions): Promise<ArchiveContent>;
@@ -0,0 +1,75 @@
1
+ import { Worker } from "node:worker_threads";
2
+ import { archiveFormat as detectArchiveFormat } from "./archive-engine.js";
3
+ export { MAX_ARCHIVE_ENTRIES, MAX_ARCHIVE_ENTRY_BYTES, MAX_ARCHIVE_FILE_BYTES, MAX_ARCHIVE_PATH_BYTES, MAX_ARCHIVE_MANIFEST_PATH_BYTES, MAX_ARCHIVE_SCAN_BYTES } from "./archive-engine.js";
4
+ const MAX_CONCURRENT_ARCHIVE_JOBS = 2;
5
+ const MAX_QUEUED_ARCHIVE_JOBS = 32;
6
+ const ARCHIVE_JOB_TIMEOUT_MS = 15_000;
7
+ export class ArchiveError extends Error {
8
+ status;
9
+ code;
10
+ constructor(status, code, message = code) {
11
+ super(message);
12
+ this.status = status;
13
+ this.code = code;
14
+ }
15
+ }
16
+ let active = 0;
17
+ const activeKeys = new Set(), queue = [];
18
+ export function archiveFormat(file) { return detectArchiveFormat(file); }
19
+ export function isArchivePath(file) { return archiveFormat(file) !== undefined; }
20
+ function schedule() {
21
+ while (active < MAX_CONCURRENT_ARCHIVE_JOBS) {
22
+ const index = queue.findIndex(job => !activeKeys.has(job.key));
23
+ if (index < 0)
24
+ return;
25
+ const [job] = queue.splice(index, 1);
26
+ if (job.queuedAbort)
27
+ job.signal?.removeEventListener("abort", job.queuedAbort);
28
+ if (job.signal?.aborted) {
29
+ job.reject(new ArchiveError(499, "archive_request_aborted"));
30
+ continue;
31
+ }
32
+ active++;
33
+ activeKeys.add(job.key);
34
+ void job.start().then(job.resolve, job.reject).finally(() => { active--; activeKeys.delete(job.key); schedule(); });
35
+ }
36
+ }
37
+ function limited(key, signal, start) {
38
+ if (signal?.aborted)
39
+ return Promise.reject(new ArchiveError(499, "archive_request_aborted"));
40
+ if (queue.length >= MAX_QUEUED_ARCHIVE_JOBS)
41
+ return Promise.reject(new ArchiveError(429, "archive_queue_full", "too many archive preview requests"));
42
+ return new Promise((resolve, reject) => { const job = { key, start, resolve: resolve, reject, signal }; const abort = () => { const index = queue.indexOf(job); if (index >= 0) {
43
+ queue.splice(index, 1);
44
+ reject(new ArchiveError(499, "archive_request_aborted"));
45
+ } }; job.queuedAbort = abort; signal?.addEventListener("abort", abort, { once: true }); queue.push(job); schedule(); });
46
+ }
47
+ function runWorker(input, signal) {
48
+ return new Promise((resolve, reject) => {
49
+ const workerFile = new URL(import.meta.url.endsWith(".ts") ? "./archive-worker.ts" : "./archive-worker.js", import.meta.url);
50
+ const worker = new Worker(workerFile, { workerData: input, resourceLimits: { maxOldGenerationSizeMb: 128, maxYoungGenerationSizeMb: 16, stackSizeMb: 4 } });
51
+ let settled = false;
52
+ const finish = (error, value) => { if (settled)
53
+ return; settled = true; clearTimeout(timer); signal?.removeEventListener("abort", onAbort); void worker.terminate(); error ? reject(error) : resolve(value); };
54
+ const onAbort = () => finish(new ArchiveError(499, "archive_request_aborted"));
55
+ const timer = setTimeout(() => finish(new ArchiveError(504, "archive_timeout", `archive preview exceeded ${ARCHIVE_JOB_TIMEOUT_MS}ms`)), ARCHIVE_JOB_TIMEOUT_MS);
56
+ timer.unref();
57
+ signal?.addEventListener("abort", onAbort, { once: true });
58
+ worker.once("message", message => { if (message?.ok) {
59
+ const value = message.value;
60
+ if (value?.body)
61
+ value.body = Buffer.from(value.body);
62
+ finish(undefined, value);
63
+ }
64
+ else {
65
+ const e = message?.error;
66
+ finish(new ArchiveError(Number(e?.status) || 422, String(e?.code || "invalid_archive"), String(e?.message || "archive processing failed")));
67
+ } });
68
+ worker.once("error", error => finish(new ArchiveError(422, "archive_worker_failed", error.message)));
69
+ worker.once("exit", code => { if (!settled)
70
+ finish(new ArchiveError(422, "archive_worker_failed", `archive worker exited with code ${code}`)); });
71
+ });
72
+ }
73
+ export async function listArchive(file, options = { expectedRealPath: file, key: file }) { return limited(options.key, options.signal, () => runWorker({ action: "list", file, expectedRealPath: options.expectedRealPath }, options.signal)); }
74
+ export async function readArchiveEntry(file, rawEntry, options = { expectedRealPath: file, key: file }) { return limited(options.key, options.signal, () => runWorker({ action: "read", file, expectedRealPath: options.expectedRealPath, entry: rawEntry }, options.signal)); }
75
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../src/archive.ts"],"names":[],"mappings":"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"}