archive-codec 1.0.2 → 1.1.1
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 +44 -7
- package/dist/cfb/detect.cjs +18 -0
- package/dist/cfb/detect.d.cts +4 -0
- package/dist/cfb/detect.d.ts +4 -0
- package/dist/cfb/detect.js +17 -0
- package/dist/cfb/ole-package.cjs +42 -0
- package/dist/cfb/ole-package.d.cts +13 -0
- package/dist/cfb/ole-package.d.ts +13 -0
- package/dist/cfb/ole-package.js +40 -0
- package/dist/cfb/read.cjs +206 -0
- package/dist/cfb/read.d.cts +15 -0
- package/dist/cfb/read.d.ts +15 -0
- package/dist/cfb/read.js +203 -0
- package/dist/index.cjs +20 -79
- package/dist/index.d.cts +7 -33
- package/dist/index.d.ts +7 -33
- package/dist/index.js +7 -72
- package/dist/magic.cjs +9 -0
- package/dist/magic.d.cts +4 -0
- package/dist/magic.d.ts +4 -0
- package/dist/magic.js +8 -0
- package/dist/zip/container.cjs +15 -0
- package/dist/zip/container.d.cts +9 -0
- package/dist/zip/container.d.ts +9 -0
- package/dist/zip/container.js +13 -0
- package/dist/zip/detect.cjs +26 -0
- package/dist/zip/detect.d.cts +6 -0
- package/dist/zip/detect.d.ts +6 -0
- package/dist/zip/detect.js +24 -0
- package/dist/zip/walk.cjs +41 -0
- package/dist/zip/walk.d.cts +20 -0
- package/dist/zip/walk.d.ts +20 -0
- package/dist/zip/walk.js +37 -0
- package/package.json +6 -4
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_zip_container = require("./container.cjs");
|
|
3
|
+
const require_zip_detect = require("./detect.cjs");
|
|
4
|
+
//#region src/zip/walk.ts
|
|
5
|
+
const MAX_WALK_DEPTH = 8;
|
|
6
|
+
const MAX_WALK_TOTAL_BYTES = 536870912;
|
|
7
|
+
var ArchiveWalkLimitError = class extends Error {
|
|
8
|
+
limit;
|
|
9
|
+
constructor(limit, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "ArchiveWalkLimitError";
|
|
12
|
+
this.limit = limit;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function walkArchive(bytes, options = {}) {
|
|
16
|
+
const maxDepth = options.maxDepth ?? 8;
|
|
17
|
+
const maxTotalBytes = options.maxTotalBytes ?? 536870912;
|
|
18
|
+
if (!require_zip_detect.isZipArchive(bytes)) throw new Error("walkArchive input is not a ZIP archive (leading magic bytes are not PK\\x03\\x04 or PK\\x05\\x06)");
|
|
19
|
+
const entries = [];
|
|
20
|
+
let totalBytes = 0;
|
|
21
|
+
visit(bytes, []);
|
|
22
|
+
return entries;
|
|
23
|
+
function visit(archive, ancestors) {
|
|
24
|
+
if (ancestors.length + 1 > maxDepth) throw new ArchiveWalkLimitError("depth", `archive nesting exceeds the maximum walk depth of ${maxDepth} at ${ancestors.join(" > ")}`);
|
|
25
|
+
for (const [path, entryBytes] of Object.entries(require_zip_container.unzipPackage(archive))) {
|
|
26
|
+
totalBytes += entryBytes.length;
|
|
27
|
+
if (totalBytes > maxTotalBytes) throw new ArchiveWalkLimitError("total-bytes", `cumulative decompressed size of the walk exceeded the ${maxTotalBytes}-byte budget at ${path}`);
|
|
28
|
+
entries.push({
|
|
29
|
+
path,
|
|
30
|
+
ancestors,
|
|
31
|
+
bytes: entryBytes
|
|
32
|
+
});
|
|
33
|
+
if (require_zip_detect.isZipArchive(entryBytes)) visit(entryBytes, [...ancestors, path]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
exports.ArchiveWalkLimitError = ArchiveWalkLimitError;
|
|
39
|
+
exports.MAX_WALK_DEPTH = MAX_WALK_DEPTH;
|
|
40
|
+
exports.MAX_WALK_TOTAL_BYTES = MAX_WALK_TOTAL_BYTES;
|
|
41
|
+
exports.walkArchive = walkArchive;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/zip/walk.d.ts
|
|
2
|
+
declare const MAX_WALK_DEPTH = 8;
|
|
3
|
+
declare const MAX_WALK_TOTAL_BYTES: number;
|
|
4
|
+
interface ArchiveWalkEntry {
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly ancestors: readonly string[];
|
|
7
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
8
|
+
}
|
|
9
|
+
type ArchiveWalkLimit = 'depth' | 'total-bytes';
|
|
10
|
+
declare class ArchiveWalkLimitError extends Error {
|
|
11
|
+
readonly limit: ArchiveWalkLimit;
|
|
12
|
+
constructor(limit: ArchiveWalkLimit, message: string);
|
|
13
|
+
}
|
|
14
|
+
interface WalkArchiveOptions {
|
|
15
|
+
readonly maxDepth?: number;
|
|
16
|
+
readonly maxTotalBytes?: number;
|
|
17
|
+
}
|
|
18
|
+
declare function walkArchive(bytes: Uint8Array<ArrayBuffer>, options?: WalkArchiveOptions): ArchiveWalkEntry[];
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ArchiveWalkEntry, ArchiveWalkLimit, ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, WalkArchiveOptions, walkArchive };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/zip/walk.d.ts
|
|
2
|
+
declare const MAX_WALK_DEPTH = 8;
|
|
3
|
+
declare const MAX_WALK_TOTAL_BYTES: number;
|
|
4
|
+
interface ArchiveWalkEntry {
|
|
5
|
+
readonly path: string;
|
|
6
|
+
readonly ancestors: readonly string[];
|
|
7
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
8
|
+
}
|
|
9
|
+
type ArchiveWalkLimit = 'depth' | 'total-bytes';
|
|
10
|
+
declare class ArchiveWalkLimitError extends Error {
|
|
11
|
+
readonly limit: ArchiveWalkLimit;
|
|
12
|
+
constructor(limit: ArchiveWalkLimit, message: string);
|
|
13
|
+
}
|
|
14
|
+
interface WalkArchiveOptions {
|
|
15
|
+
readonly maxDepth?: number;
|
|
16
|
+
readonly maxTotalBytes?: number;
|
|
17
|
+
}
|
|
18
|
+
declare function walkArchive(bytes: Uint8Array<ArrayBuffer>, options?: WalkArchiveOptions): ArchiveWalkEntry[];
|
|
19
|
+
//#endregion
|
|
20
|
+
export { ArchiveWalkEntry, ArchiveWalkLimit, ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, WalkArchiveOptions, walkArchive };
|
package/dist/zip/walk.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { unzipPackage } from "./container.js";
|
|
2
|
+
import { isZipArchive } from "./detect.js";
|
|
3
|
+
//#region src/zip/walk.ts
|
|
4
|
+
const MAX_WALK_DEPTH = 8;
|
|
5
|
+
const MAX_WALK_TOTAL_BYTES = 536870912;
|
|
6
|
+
var ArchiveWalkLimitError = class extends Error {
|
|
7
|
+
limit;
|
|
8
|
+
constructor(limit, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "ArchiveWalkLimitError";
|
|
11
|
+
this.limit = limit;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function walkArchive(bytes, options = {}) {
|
|
15
|
+
const maxDepth = options.maxDepth ?? 8;
|
|
16
|
+
const maxTotalBytes = options.maxTotalBytes ?? 536870912;
|
|
17
|
+
if (!isZipArchive(bytes)) throw new Error("walkArchive input is not a ZIP archive (leading magic bytes are not PK\\x03\\x04 or PK\\x05\\x06)");
|
|
18
|
+
const entries = [];
|
|
19
|
+
let totalBytes = 0;
|
|
20
|
+
visit(bytes, []);
|
|
21
|
+
return entries;
|
|
22
|
+
function visit(archive, ancestors) {
|
|
23
|
+
if (ancestors.length + 1 > maxDepth) throw new ArchiveWalkLimitError("depth", `archive nesting exceeds the maximum walk depth of ${maxDepth} at ${ancestors.join(" > ")}`);
|
|
24
|
+
for (const [path, entryBytes] of Object.entries(unzipPackage(archive))) {
|
|
25
|
+
totalBytes += entryBytes.length;
|
|
26
|
+
if (totalBytes > maxTotalBytes) throw new ArchiveWalkLimitError("total-bytes", `cumulative decompressed size of the walk exceeded the ${maxTotalBytes}-byte budget at ${path}`);
|
|
27
|
+
entries.push({
|
|
28
|
+
path,
|
|
29
|
+
ancestors,
|
|
30
|
+
bytes: entryBytes
|
|
31
|
+
});
|
|
32
|
+
if (isZipArchive(entryBytes)) visit(entryBytes, [...ancestors, path]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ArchiveWalkLimitError, MAX_WALK_DEPTH, MAX_WALK_TOTAL_BYTES, walkArchive };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archive-codec",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "ZIP-in-ZIP recursive walking with depth and cumulative decompressed-size guards, plus bounded classic OLE compound-file ([MS-CFB]) reading - zero document-format knowledge, the archive and container utility package for the documents.js family.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -57,10 +57,12 @@
|
|
|
57
57
|
"_typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
|
|
58
58
|
"_typecheck:attw": "attw --pack",
|
|
59
59
|
"test": "turbo run _test",
|
|
60
|
-
"_test": "vitest run",
|
|
61
|
-
"test:watch": "vitest",
|
|
60
|
+
"_test": "vitest run --project unit",
|
|
61
|
+
"test:watch": "vitest --project unit",
|
|
62
62
|
"test:workers": "turbo run _test:workers",
|
|
63
63
|
"_test:workers": "vitest run --config vitest.workers.config.ts",
|
|
64
|
+
"test:smoke": "turbo run _test:smoke",
|
|
65
|
+
"_test:smoke": "vitest run --project smoke",
|
|
64
66
|
"prepare": "husky"
|
|
65
67
|
},
|
|
66
68
|
"packageManager": "pnpm@11.6.0",
|