@procedures/archive 0.0.0-stage → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -2
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/errors.d.ts +27 -0
  5. package/dist/errors.d.ts.map +1 -0
  6. package/dist/errors.js +15 -0
  7. package/dist/errors.js.map +1 -0
  8. package/dist/format.d.ts +25 -0
  9. package/dist/format.d.ts.map +1 -0
  10. package/dist/format.js +60 -0
  11. package/dist/format.js.map +1 -0
  12. package/dist/index.d.ts +8 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +10 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/module.d.ts +34 -0
  17. package/dist/module.d.ts.map +1 -0
  18. package/dist/module.js +148 -0
  19. package/dist/module.js.map +1 -0
  20. package/dist/paths.d.ts +58 -0
  21. package/dist/paths.d.ts.map +1 -0
  22. package/dist/paths.js +205 -0
  23. package/dist/paths.js.map +1 -0
  24. package/dist/procedures/archive/create.d.ts +14 -0
  25. package/dist/procedures/archive/create.d.ts.map +1 -0
  26. package/dist/procedures/archive/create.js +81 -0
  27. package/dist/procedures/archive/create.js.map +1 -0
  28. package/dist/procedures/archive/extract.d.ts +17 -0
  29. package/dist/procedures/archive/extract.d.ts.map +1 -0
  30. package/dist/procedures/archive/extract.js +101 -0
  31. package/dist/procedures/archive/extract.js.map +1 -0
  32. package/dist/procedures/archive/index.d.ts +4 -0
  33. package/dist/procedures/archive/index.d.ts.map +1 -0
  34. package/dist/procedures/archive/index.js +4 -0
  35. package/dist/procedures/archive/index.js.map +1 -0
  36. package/dist/procedures/archive/list.d.ts +15 -0
  37. package/dist/procedures/archive/list.d.ts.map +1 -0
  38. package/dist/procedures/archive/list.js +47 -0
  39. package/dist/procedures/archive/list.js.map +1 -0
  40. package/dist/register.d.ts +6 -0
  41. package/dist/register.d.ts.map +1 -0
  42. package/dist/register.js +8 -0
  43. package/dist/register.js.map +1 -0
  44. package/dist/tar.d.ts +38 -0
  45. package/dist/tar.d.ts.map +1 -0
  46. package/dist/tar.js +193 -0
  47. package/dist/tar.js.map +1 -0
  48. package/dist/types.d.ts +81 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +8 -0
  51. package/dist/types.js.map +1 -0
  52. package/dist/walk.d.ts +34 -0
  53. package/dist/walk.d.ts.map +1 -0
  54. package/dist/walk.js +67 -0
  55. package/dist/walk.js.map +1 -0
  56. package/dist/zip.d.ts +57 -0
  57. package/dist/zip.d.ts.map +1 -0
  58. package/dist/zip.js +397 -0
  59. package/dist/zip.js.map +1 -0
  60. package/package.json +77 -3
  61. package/src/errors.ts +33 -0
  62. package/src/format.ts +64 -0
  63. package/src/index.ts +9 -0
  64. package/src/module.ts +192 -0
  65. package/src/paths.ts +230 -0
  66. package/src/procedures/archive/create.ts +84 -0
  67. package/src/procedures/archive/extract.ts +103 -0
  68. package/src/procedures/archive/index.ts +3 -0
  69. package/src/procedures/archive/list.ts +50 -0
  70. package/src/register.ts +10 -0
  71. package/src/tar.ts +198 -0
  72. package/src/types.ts +101 -0
  73. package/src/walk.ts +85 -0
  74. package/src/zip.ts +419 -0
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The format of an archive: from the name of a new archive, or from the first bytes of a file.
3
+ * And the limits of the module.
4
+ */
5
+ import type { ArchiveFormat } from "./types.js";
6
+ /** The limits of the procedures of a module. */
7
+ export interface ArchiveSettings {
8
+ /** The most bytes of the files of one archive: `extract` and `create` refuse more. */
9
+ readonly maxBytes: number;
10
+ /** The most entries of one archive. */
11
+ readonly maxEntries: number;
12
+ }
13
+ /** The default most bytes: 1 GiB. */
14
+ export declare const DEFAULT_MAX_BYTES: number;
15
+ /** The default most entries. */
16
+ export declare const DEFAULT_MAX_ENTRIES = 100000;
17
+ /** The settings of the default module. */
18
+ export declare const DEFAULT_ARCHIVE_SETTINGS: ArchiveSettings;
19
+ /** The format of a new archive from its name, or the format of the input. */
20
+ export declare function formatOfName(path: string, given: ArchiveFormat | undefined): ArchiveFormat;
21
+ /** The format that the first bytes of a file show, or undefined. */
22
+ export declare function sniffFormat(path: string): Promise<ArchiveFormat | undefined>;
23
+ /** The format of an existing archive: its first bytes, which must agree with the format of the input. */
24
+ export declare function formatOfFile(path: string, given: ArchiveFormat | undefined): Promise<ArchiveFormat>;
25
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,EAAE,MAA2B,CAAC;AAC5D,gCAAgC;AAChC,eAAO,MAAM,mBAAmB,SAAU,CAAC;AAE3C,0CAA0C;AAC1C,eAAO,MAAM,wBAAwB,EAAE,eAAiG,CAAC;AAEzI,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAO1F;AAED,oEAAoE;AACpE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAclF;AAED,yGAAyG;AACzG,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAUzG"}
package/dist/format.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The format of an archive: from the name of a new archive, or from the first bytes of a file.
3
+ * And the limits of the module.
4
+ */
5
+ import { open } from "node:fs/promises";
6
+ import { ArchiveError } from "./errors.js";
7
+ /** The default most bytes: 1 GiB. */
8
+ export const DEFAULT_MAX_BYTES = 1024 * 1024 * 1024;
9
+ /** The default most entries. */
10
+ export const DEFAULT_MAX_ENTRIES = 100_000;
11
+ /** The settings of the default module. */
12
+ export const DEFAULT_ARCHIVE_SETTINGS = Object.freeze({ maxBytes: DEFAULT_MAX_BYTES, maxEntries: DEFAULT_MAX_ENTRIES });
13
+ /** The format of a new archive from its name, or the format of the input. */
14
+ export function formatOfName(path, given) {
15
+ if (given !== undefined)
16
+ return given;
17
+ const name = path.toLowerCase();
18
+ if (name.endsWith(".tar.gz") || name.endsWith(".tgz"))
19
+ return "tar.gz";
20
+ if (name.endsWith(".tar"))
21
+ return "tar";
22
+ if (name.endsWith(".zip"))
23
+ return "zip";
24
+ throw new ArchiveError("BAD_FORMAT", `The name ${path} does not tell the format: give format, or end the name with .tar.gz, .tgz, .tar or .zip`);
25
+ }
26
+ /** The format that the first bytes of a file show, or undefined. */
27
+ export async function sniffFormat(path) {
28
+ const handle = await open(path, "r");
29
+ try {
30
+ const head = Buffer.alloc(512);
31
+ const { bytesRead } = await handle.read(head, 0, 512, 0);
32
+ if (bytesRead >= 2 && head[0] === 0x1f && head[1] === 0x8b)
33
+ return "tar.gz";
34
+ if (bytesRead >= 4 && head[0] === 0x50 && head[1] === 0x4b && ((head[2] === 3 && head[3] === 4) || (head[2] === 5 && head[3] === 6)))
35
+ return "zip";
36
+ if (bytesRead >= 262 && head.toString("latin1", 257, 262) === "ustar")
37
+ return "tar";
38
+ // An empty tar: zero blocks without a header
39
+ if (bytesRead === 512 && head.every((byte) => byte === 0))
40
+ return "tar";
41
+ return undefined;
42
+ }
43
+ finally {
44
+ await handle.close();
45
+ }
46
+ }
47
+ /** The format of an existing archive: its first bytes, which must agree with the format of the input. */
48
+ export async function formatOfFile(path, given) {
49
+ const found = await sniffFormat(path);
50
+ if (found === undefined) {
51
+ if (given === "tar")
52
+ return "tar";
53
+ throw new ArchiveError("BAD_FORMAT", `${path} is not a tar.gz, tar or zip archive`);
54
+ }
55
+ if (given !== undefined && given !== found) {
56
+ throw new ArchiveError("BAD_FORMAT", `${path} is a ${found} archive, not a ${given} archive`);
57
+ }
58
+ return found;
59
+ }
60
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export * from "./module.js";
2
+ export * from "./types.js";
3
+ export { archiveCreate, archiveExtract, archiveList } from "./procedures/archive/index.js";
4
+ export { ArchiveError, type ArchiveErrorCode } from "./errors.js";
5
+ export { DEFAULT_ARCHIVE_SETTINGS, DEFAULT_MAX_BYTES, DEFAULT_MAX_ENTRIES, formatOfFile, formatOfName, sniffFormat, type ArchiveSettings } from "./format.js";
6
+ export { entryParts, isAbsoluteName, planExtract, type PlanOptions, type PlannedEntry, type RawEntry } from "./paths.js";
7
+ export { crc32, readZipDirectory, writeZip, type ZipEntry, type ZipWriteEntry } from "./zip.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE3F,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9J,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ // The root registers nothing: import "<package>/register", or give the module to createRegistry()
2
+ export * from "./module.js";
3
+ export * from "./types.js";
4
+ export { archiveCreate, archiveExtract, archiveList } from "./procedures/archive/index.js";
5
+ // The checks and the formats (roadmap R46)
6
+ export { ArchiveError } from "./errors.js";
7
+ export { DEFAULT_ARCHIVE_SETTINGS, DEFAULT_MAX_BYTES, DEFAULT_MAX_ENTRIES, formatOfFile, formatOfName, sniffFormat } from "./format.js";
8
+ export { entryParts, isAbsoluteName, planExtract } from "./paths.js";
9
+ export { crc32, readZipDirectory, writeZip } from "./zip.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC3F,2CAA2C;AAC3C,OAAO,EAAE,YAAY,EAAyB,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAwB,MAAM,aAAa,CAAC;AAC9J,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAsD,MAAM,YAAY,CAAC;AACzH,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAqC,MAAM,UAAU,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The procedures of @procedures/archive as data. Importing this file registers nothing.
3
+ *
4
+ * Scaffold a procedure with: mark procedure new <name> --path packages/archive
5
+ *
6
+ * `archiveModule` has the default limits: 1 GiB of files and 100000 entries in one archive.
7
+ * `createArchiveModule()` gives the same procedures with other limits (roadmap R46).
8
+ */
9
+ import { type ProcedureModule, type ProcedureRegistry } from "@procedures/client";
10
+ /**
11
+ * The module of this package, for `createRegistry()`: its procedures as data, with the default
12
+ * limits. Importing this file registers nothing.
13
+ */
14
+ export declare const archiveModule: ProcedureModule;
15
+ export default archiveModule;
16
+ /** The options of `createArchiveModule()`. */
17
+ export interface ArchiveModuleOptions {
18
+ /** The most bytes of the files of one archive. The default is 1 GiB. */
19
+ readonly maxBytes?: number | undefined;
20
+ /** The most entries of one archive. The default is 100000. */
21
+ readonly maxEntries?: number | undefined;
22
+ }
23
+ /**
24
+ * This function gives the module of this package with other limits. Without options, it gives
25
+ * `archiveModule`. A host gives it to `createRegistry()` before its bundles, so it replaces the
26
+ * `archiveModule` that a bundle requires (the first module of a name counts).
27
+ */
28
+ export declare function createArchiveModule(options?: ArchiveModuleOptions): ProcedureModule;
29
+ /**
30
+ * This function registers the procedures of @procedures/archive in a registry. The default is the
31
+ * global registry. The options are the options of `createArchiveModule()`.
32
+ */
33
+ export declare function registerArchiveProcedures(registry?: ProcedureRegistry, options?: ArchiveModuleOptions): void;
34
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAQL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAoI5B;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eAAkG,CAAC;eAEhH,aAAa;AAE5B,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,eAAe,CAUvF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,GAAE,iBAAsC,EAAE,OAAO,GAAE,oBAAyB,GAAG,IAAI,CAEpI"}
package/dist/module.js ADDED
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The procedures of @procedures/archive as data. Importing this file registers nothing.
3
+ *
4
+ * Scaffold a procedure with: mark procedure new <name> --path packages/archive
5
+ *
6
+ * `archiveModule` has the default limits: 1 GiB of files and 100000 entries in one archive.
7
+ * `createArchiveModule()` gives the same procedures with other limits (roadmap R46).
8
+ */
9
+ import { z } from "zod";
10
+ import { defineModule, registerModules, PROCEDURE_REGISTRY, createProcedure, zodAdapter, } from "@procedures/client";
11
+ import { archiveCreate } from "./procedures/archive/create.js";
12
+ import { archiveExtract } from "./procedures/archive/extract.js";
13
+ import { archiveList } from "./procedures/archive/list.js";
14
+ import { DEFAULT_ARCHIVE_SETTINGS } from "./format.js";
15
+ // =============================================================================
16
+ // Schemas
17
+ // =============================================================================
18
+ const path = (description) => z.string().min(1).max(4096).describe(description);
19
+ const format = z.enum(["tar.gz", "tar", "zip"]);
20
+ const ArchiveCreateInputSchema = z.object({
21
+ output: path("The archive to make"),
22
+ source: path("A folder: the archive gets its content").optional(),
23
+ files: z.array(z.string().min(1).max(4096)).min(1).max(10_000).optional().describe("Files and folders, relative to cwd. A folder goes in with its content"),
24
+ cwd: path("The base folder of files (default: the working folder)").optional(),
25
+ format: format.optional().describe("The format (default: from the name of output: .tar.gz, .tgz, .tar or .zip)"),
26
+ overwrite: z.boolean().optional().describe("True: replace an existing archive (default false)"),
27
+ });
28
+ const ArchiveCreateOutputSchema = z.object({
29
+ path: z.string().describe("The absolute path of the archive"),
30
+ format,
31
+ entries: z.number().int().describe("The number of entries: files, folders and links"),
32
+ bytes: z.number().int().describe("The size of the archive, in bytes"),
33
+ });
34
+ const ArchiveExtractInputSchema = z.object({
35
+ archive: path("The archive"),
36
+ target: path("The folder that gets the content. The procedure makes it"),
37
+ format: format.optional().describe("The format (default: from the first bytes of the archive)"),
38
+ overwrite: z.boolean().optional().describe("True: replace an existing file (default false: an existing file is an error, and nothing changes)"),
39
+ });
40
+ const ArchiveExtractOutputSchema = z.object({
41
+ target: z.string().describe("The absolute path of the target folder"),
42
+ format,
43
+ files: z.number().int(),
44
+ directories: z.number().int(),
45
+ links: z.number().int().describe("The symbolic links and the hard links"),
46
+ bytes: z.number().int().describe("The bytes of the files"),
47
+ });
48
+ const ArchiveListInputSchema = z.object({
49
+ archive: path("The archive"),
50
+ format: format.optional().describe("The format (default: from the first bytes of the archive)"),
51
+ });
52
+ const ArchiveListOutputSchema = z.object({
53
+ format,
54
+ entries: z.array(z.object({
55
+ path: z.string().describe("The path in the archive"),
56
+ kind: z.enum(["file", "directory", "symlink", "hardlink", "other"]),
57
+ size: z.number().int(),
58
+ mode: z.number().int().optional(),
59
+ mtime: z.string().optional().describe("The time of the last change, as an ISO text"),
60
+ linkTarget: z.string().optional().describe("The target of a link"),
61
+ })),
62
+ bytes: z.number().int().describe("The sum of the sizes of the files"),
63
+ });
64
+ // =============================================================================
65
+ // Procedures
66
+ // =============================================================================
67
+ /** The effects of `create` and `extract`: they read and write files, and `overwrite` replaces a file. */
68
+ const READS_WRITES_FS = Object.freeze({ reads: Object.freeze(["fs"]), writes: Object.freeze(["fs"]) });
69
+ /** The effects of `list`: it reads a file and changes nothing. */
70
+ const READS_FS = Object.freeze({ reads: Object.freeze(["fs"]), writes: Object.freeze([]) });
71
+ /** The three procedures, with handlers that use the limits. */
72
+ function archiveProcedures(settings) {
73
+ const archiveCreateProcedure = createProcedure()
74
+ .path(["archive", "create"])
75
+ .input(zodAdapter(ArchiveCreateInputSchema))
76
+ .output(zodAdapter(ArchiveCreateOutputSchema))
77
+ .meta({
78
+ description: "Make a tar.gz or zip archive of a folder or of files",
79
+ tags: ["archive", "fs"],
80
+ args: ["output"],
81
+ shorts: { source: "s", format: "f" },
82
+ output: "json",
83
+ effects: READS_WRITES_FS,
84
+ })
85
+ .handler(async (input) => archiveCreate(input, settings))
86
+ .build();
87
+ const archiveExtractProcedure = createProcedure()
88
+ .path(["archive", "extract"])
89
+ .input(zodAdapter(ArchiveExtractInputSchema))
90
+ .output(zodAdapter(ArchiveExtractOutputSchema))
91
+ .meta({
92
+ description: "Extract a tar.gz or zip archive into a folder, with a check of each path",
93
+ tags: ["archive", "fs"],
94
+ args: ["archive", "target"],
95
+ shorts: { format: "f" },
96
+ output: "json",
97
+ effects: READS_WRITES_FS,
98
+ })
99
+ .handler(async (input) => archiveExtract(input, settings))
100
+ .build();
101
+ const archiveListProcedure = createProcedure()
102
+ .path(["archive", "list"])
103
+ .input(zodAdapter(ArchiveListInputSchema))
104
+ .output(zodAdapter(ArchiveListOutputSchema))
105
+ .meta({
106
+ description: "The entries of a tar.gz or zip archive",
107
+ tags: ["archive", "fs"],
108
+ args: ["archive"],
109
+ shorts: { format: "f" },
110
+ output: "json",
111
+ effects: READS_FS,
112
+ })
113
+ .handler(async (input) => archiveList(input, settings))
114
+ .build();
115
+ return [archiveCreateProcedure, archiveExtractProcedure, archiveListProcedure];
116
+ }
117
+ /**
118
+ * The module of this package, for `createRegistry()`: its procedures as data, with the default
119
+ * limits. Importing this file registers nothing.
120
+ */
121
+ export const archiveModule = defineModule("@procedures/archive", archiveProcedures(DEFAULT_ARCHIVE_SETTINGS));
122
+ export default archiveModule;
123
+ /**
124
+ * This function gives the module of this package with other limits. Without options, it gives
125
+ * `archiveModule`. A host gives it to `createRegistry()` before its bundles, so it replaces the
126
+ * `archiveModule` that a bundle requires (the first module of a name counts).
127
+ */
128
+ export function createArchiveModule(options = {}) {
129
+ if (Object.values(options).every((value) => value === undefined))
130
+ return archiveModule;
131
+ const settings = {
132
+ maxBytes: options.maxBytes ?? DEFAULT_ARCHIVE_SETTINGS.maxBytes,
133
+ maxEntries: options.maxEntries ?? DEFAULT_ARCHIVE_SETTINGS.maxEntries,
134
+ };
135
+ for (const [name, value] of Object.entries(settings)) {
136
+ if (!Number.isSafeInteger(value) || value < 0)
137
+ throw new TypeError(`createArchiveModule: ${name} must be a whole number of 0 or more`);
138
+ }
139
+ return defineModule("@procedures/archive", archiveProcedures(settings));
140
+ }
141
+ /**
142
+ * This function registers the procedures of @procedures/archive in a registry. The default is the
143
+ * global registry. The options are the options of `createArchiveModule()`.
144
+ */
145
+ export function registerArchiveProcedures(registry = PROCEDURE_REGISTRY, options = {}) {
146
+ registerModules(registry, [createArchiveModule(options)]);
147
+ }
148
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,UAAU,GAKX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAwB,MAAM,aAAa,CAAC;AAU7E,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,MAAM,IAAI,GAAG,CAAC,WAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACxF,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAEhD,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,IAAI,CAAC,qBAAqB,CAAC;IACnC,MAAM,EAAE,IAAI,CAAC,wCAAwC,CAAC,CAAC,QAAQ,EAAE;IACjE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uEAAuE,CAAC;IAC3J,GAAG,EAAE,IAAI,CAAC,wDAAwD,CAAC,CAAC,QAAQ,EAAE;IAC9E,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;IAChH,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC;CAChG,CAAC,CAAC;AAEH,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAC7D,MAAM;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACrF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;IAC5B,MAAM,EAAE,IAAI,CAAC,0DAA0D,CAAC;IACxE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;IAC/F,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mGAAmG,CAAC;CAChJ,CAAC,CAAC;AAEH,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IACrE,MAAM;IACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IACzE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;CAC3D,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;CAChG,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM;IACN,OAAO,EAAE,CAAC,CAAC,KAAK,CACd,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QACnE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;QACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QACjC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;QACpF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACnE,CAAC,CACH;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;CACtE,CAAC,CAAC;AAEH,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,yGAAyG;AACzG,MAAM,eAAe,GAAY,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;AAChH,kEAAkE;AAClE,MAAM,QAAQ,GAAY,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAErG,+DAA+D;AAC/D,SAAS,iBAAiB,CAAC,QAAyB;IAClD,MAAM,sBAAsB,GAAG,eAAe,EAAE;SAC7C,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;SAC3B,KAAK,CAAC,UAAU,CAAqB,wBAAwB,CAAC,CAAC;SAC/D,MAAM,CAAC,UAAU,CAAsB,yBAAyB,CAAC,CAAC;SAClE,IAAI,CAAC;QACJ,WAAW,EAAE,sDAAsD;QACnE,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC;QACvB,IAAI,EAAE,CAAC,QAAQ,CAAC;QAChB,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;QACpC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,eAAe;KACzB,CAAC;SACD,OAAO,CAAC,KAAK,EAAE,KAAyB,EAAgC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;SAC1G,KAAK,EAAE,CAAC;IAEX,MAAM,uBAAuB,GAAG,eAAe,EAAE;SAC9C,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;SAC5B,KAAK,CAAC,UAAU,CAAsB,yBAAyB,CAAC,CAAC;SACjE,MAAM,CAAC,UAAU,CAAuB,0BAA0B,CAAC,CAAC;SACpE,IAAI,CAAC;QACJ,WAAW,EAAE,0EAA0E;QACvF,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC;QACvB,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;QAC3B,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;QACvB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,eAAe;KACzB,CAAC;SACD,OAAO,CAAC,KAAK,EAAE,KAA0B,EAAiC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;SAC7G,KAAK,EAAE,CAAC;IAEX,MAAM,oBAAoB,GAAG,eAAe,EAAE;SAC3C,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;SACzB,KAAK,CAAC,UAAU,CAAmB,sBAAsB,CAAC,CAAC;SAC3D,MAAM,CAAC,UAAU,CAAoB,uBAAuB,CAAC,CAAC;SAC9D,IAAI,CAAC;QACJ,WAAW,EAAE,wCAAwC;QACrD,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC;QACvB,IAAI,EAAE,CAAC,SAAS,CAAC;QACjB,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;QACvB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,QAAQ;KAClB,CAAC;SACD,OAAO,CAAC,KAAK,EAAE,KAAuB,EAA8B,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;SACpG,KAAK,EAAE,CAAC;IAEX,OAAO,CAAC,sBAAsB,EAAE,uBAAuB,EAAE,oBAAoB,CAAC,CAAC;AACjF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAoB,YAAY,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAE/H,eAAe,aAAa,CAAC;AAU7B;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAO,GAAyB,EAAE;IACpE,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;QAAE,OAAO,aAAa,CAAC;IACvF,MAAM,QAAQ,GAAoB;QAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,wBAAwB,CAAC,QAAQ;QAC/D,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,wBAAwB,CAAC,UAAU;KACtE,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,wBAAwB,IAAI,sCAAsC,CAAC,CAAC;IACzI,CAAC;IACD,OAAO,YAAY,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAQ,GAAsB,kBAAkB,EAAE,OAAO,GAAyB,EAAE;IAC5H,eAAe,CAAC,QAAQ,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The check of the entries of an archive before an extract ("zip slip", roadmap R46).
3
+ *
4
+ * `planExtract()` examines all the entries before the extract writes a file. A hostile archive
5
+ * thus changes nothing. The rules:
6
+ *
7
+ * 1. A path must be relative and must not have `..`. A drive letter, a UNC path, a NUL character
8
+ * and (on Windows) a colon are refused too. A backslash counts as a separator.
9
+ * 2. An entry must not go through a symbolic link of the archive: a link `a` and a file `a/b`.
10
+ * 3. A symbolic link must stay in the target. Its target is relative, and the resolution through
11
+ * the other links of the archive stays in the target folder. The check knows all the links of
12
+ * the archive first, so the order of the entries does not matter.
13
+ * 4. A path of a link appears only one time in the archive.
14
+ * 5. A hard link names a file that came before it in the archive.
15
+ * 6. A folder of the target that the extract goes through must not be a symbolic link.
16
+ * 7. Without `overwrite`, an existing file at the path of an entry is an error.
17
+ *
18
+ * Rules 2 and 3 compare the paths two times: with the case, and without the case. A file system
19
+ * that ignores the case (Windows, macOS) then gets the same protection as one that does not.
20
+ */
21
+ import type { ArchiveEntryKind } from "./types.js";
22
+ /** One entry of an archive, before the check. */
23
+ export interface RawEntry {
24
+ /** The name in the archive. */
25
+ readonly name: string;
26
+ readonly kind: ArchiveEntryKind;
27
+ readonly size: number;
28
+ /** The target of a symbolic link, or the archive path of the file of a hard link. */
29
+ readonly linkTarget?: string | undefined;
30
+ /** The place of the entry in the archive. */
31
+ readonly index?: number | undefined;
32
+ }
33
+ /** One entry after the check. */
34
+ export interface PlannedEntry extends RawEntry {
35
+ /** The parts of the path: no empty part, no `.` and no `..`. */
36
+ readonly parts: readonly string[];
37
+ /** The parts joined with `/`. */
38
+ readonly path: string;
39
+ }
40
+ /** The options of `planExtract()`. */
41
+ export interface PlanOptions {
42
+ readonly overwrite: boolean;
43
+ readonly maxBytes: number;
44
+ readonly maxEntries: number;
45
+ }
46
+ /** True for a path that starts at a root: `/x`, `\x`, `C:x`, `C:\x` or `\\server\share`. */
47
+ export declare function isAbsoluteName(name: string): boolean;
48
+ /**
49
+ * This function gives the parts of the path of an entry. It throws `UNSAFE_PATH` for an absolute
50
+ * path, a `..`, a NUL character, and on Windows a colon (an alternate data stream).
51
+ */
52
+ export declare function entryParts(name: string, code?: "UNSAFE_PATH" | "UNSAFE_LINK"): string[];
53
+ /**
54
+ * This function examines the entries of an archive for an extract into `target` (a real path),
55
+ * and gives them with their parts. It throws the first problem. It writes nothing.
56
+ */
57
+ export declare function planExtract(entries: readonly RawEntry[], target: string, options: PlanOptions): PlannedEntry[];
58
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,iDAAiD;AACjD,MAAM,WAAW,QAAQ;IACvB,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,iCAAiC;AACjC,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAOD,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAa,GAAG,aAA6B,GAAG,MAAM,EAAE,CAStG;AA2DD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY,EAAE,CA0F9G"}
package/dist/paths.js ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The check of the entries of an archive before an extract ("zip slip", roadmap R46).
3
+ *
4
+ * `planExtract()` examines all the entries before the extract writes a file. A hostile archive
5
+ * thus changes nothing. The rules:
6
+ *
7
+ * 1. A path must be relative and must not have `..`. A drive letter, a UNC path, a NUL character
8
+ * and (on Windows) a colon are refused too. A backslash counts as a separator.
9
+ * 2. An entry must not go through a symbolic link of the archive: a link `a` and a file `a/b`.
10
+ * 3. A symbolic link must stay in the target. Its target is relative, and the resolution through
11
+ * the other links of the archive stays in the target folder. The check knows all the links of
12
+ * the archive first, so the order of the entries does not matter.
13
+ * 4. A path of a link appears only one time in the archive.
14
+ * 5. A hard link names a file that came before it in the archive.
15
+ * 6. A folder of the target that the extract goes through must not be a symbolic link.
16
+ * 7. Without `overwrite`, an existing file at the path of an entry is an error.
17
+ *
18
+ * Rules 2 and 3 compare the paths two times: with the case, and without the case. A file system
19
+ * that ignores the case (Windows, macOS) then gets the same protection as one that does not.
20
+ */
21
+ import { lstatSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { ArchiveError } from "./errors.js";
24
+ /** The longest chain of links that a resolution follows. More is a loop. */
25
+ const MAX_LINK_STEPS = 40;
26
+ const isWindows = process.platform === "win32";
27
+ /** True for a path that starts at a root: `/x`, `\x`, `C:x`, `C:\x` or `\\server\share`. */
28
+ export function isAbsoluteName(name) {
29
+ return /^[/\\]/.test(name) || /^[A-Za-z]:/.test(name);
30
+ }
31
+ /**
32
+ * This function gives the parts of the path of an entry. It throws `UNSAFE_PATH` for an absolute
33
+ * path, a `..`, a NUL character, and on Windows a colon (an alternate data stream).
34
+ */
35
+ export function entryParts(name, code = "UNSAFE_PATH") {
36
+ if (name.includes("\0"))
37
+ throw new ArchiveError(code, `The entry ${JSON.stringify(name)} has a NUL character`, name);
38
+ if (isAbsoluteName(name))
39
+ throw new ArchiveError(code, `The entry ${name} has an absolute path`, name);
40
+ const parts = name.split(/[/\\]+/).filter((part) => part !== "" && part !== ".");
41
+ for (const part of parts) {
42
+ if (part === "..")
43
+ throw new ArchiveError(code, `The entry ${name} has "..": it can go out of the target folder`, name);
44
+ if (isWindows && part.includes(":"))
45
+ throw new ArchiveError(code, `The entry ${name} has a colon, which Windows reads as a data stream`, name);
46
+ }
47
+ return parts;
48
+ }
49
+ /** The parts of the target of a symbolic link. `..` stays: the resolution follows it. */
50
+ function linkParts(target) {
51
+ return target.split(/[/\\]+/).filter((part) => part !== "" && part !== ".");
52
+ }
53
+ /** The key of a path, with the case or without it. */
54
+ function keyOf(parts, fold) {
55
+ const key = parts.join("/");
56
+ return fold ? key.normalize("NFC").toLowerCase() : key;
57
+ }
58
+ /** The status of a path, or undefined when it does not exist. The results stay in a cache. */
59
+ function statOf(cache, path) {
60
+ if (cache.has(path))
61
+ return cache.get(path);
62
+ let stats;
63
+ try {
64
+ stats = lstatSync(path);
65
+ }
66
+ catch {
67
+ stats = undefined;
68
+ }
69
+ cache.set(path, stats);
70
+ return stats;
71
+ }
72
+ /**
73
+ * The resolution of parts through the links of the archive: the parts of the place, or undefined
74
+ * when the resolution goes out of the root, meets an absolute link, meets a link of the target
75
+ * folder that is not in the archive, or follows too many links.
76
+ */
77
+ function resolve(parts, links, fold, foreignLink, budget) {
78
+ const place = [];
79
+ for (const part of parts) {
80
+ if (part === "..") {
81
+ if (place.length === 0)
82
+ return undefined;
83
+ place.pop();
84
+ continue;
85
+ }
86
+ place.push(part);
87
+ const target = links.get(keyOf(place, fold));
88
+ if (target === undefined) {
89
+ if (foreignLink(place))
90
+ return undefined;
91
+ continue;
92
+ }
93
+ if (--budget.steps < 0 || isAbsoluteName(target))
94
+ return undefined;
95
+ const resolved = resolve([...place.slice(0, -1), ...linkParts(target)], links, fold, foreignLink, budget);
96
+ if (resolved === undefined)
97
+ return undefined;
98
+ place.splice(0, place.length, ...resolved);
99
+ }
100
+ return place;
101
+ }
102
+ /**
103
+ * This function examines the entries of an archive for an extract into `target` (a real path),
104
+ * and gives them with their parts. It throws the first problem. It writes nothing.
105
+ */
106
+ export function planExtract(entries, target, options) {
107
+ if (entries.length > options.maxEntries) {
108
+ throw new ArchiveError("TOO_LARGE", `The archive has ${entries.length} entries, more than the limit of ${options.maxEntries}`);
109
+ }
110
+ let bytes = 0;
111
+ const planned = [];
112
+ for (const entry of entries) {
113
+ if (entry.kind === "other")
114
+ throw new ArchiveError("UNSUPPORTED_ENTRY", `The entry ${entry.name} is a special file (a device or a FIFO)`, entry.name);
115
+ const parts = entryParts(entry.name);
116
+ if (parts.length === 0) {
117
+ if (entry.kind === "directory")
118
+ continue;
119
+ throw new ArchiveError("UNSAFE_PATH", `The entry ${JSON.stringify(entry.name)} has no name`, entry.name);
120
+ }
121
+ if (entry.kind === "file") {
122
+ bytes += entry.size;
123
+ if (bytes > options.maxBytes)
124
+ throw new ArchiveError("TOO_LARGE", `The files of the archive have more than ${options.maxBytes} bytes`, entry.name);
125
+ }
126
+ planned.push({ ...entry, parts, path: parts.join("/") });
127
+ }
128
+ // The links of the archive, with the case and without it
129
+ const links = [new Map(), new Map()];
130
+ for (const entry of planned) {
131
+ if (entry.kind !== "symlink")
132
+ continue;
133
+ for (const [index, map] of links.entries())
134
+ map.set(keyOf(entry.parts, index === 1), entry.linkTarget ?? "");
135
+ }
136
+ const stats = new Map();
137
+ const foreignLink = (parts) => statOf(stats, join(target, ...parts))?.isSymbolicLink() === true;
138
+ const files = new Set();
139
+ const seenLinks = new Set();
140
+ for (const entry of planned) {
141
+ const keys = [keyOf(entry.parts, false), keyOf(entry.parts, true)];
142
+ // Rule 2: no part before the last is a link of the archive
143
+ for (let length = 1; length < entry.parts.length; length++) {
144
+ const prefix = entry.parts.slice(0, length);
145
+ if (links[0].has(keyOf(prefix, false)) || links[1].has(keyOf(prefix, true))) {
146
+ throw new ArchiveError("UNSAFE_PATH", `The entry ${entry.name} goes through the link ${prefix.join("/")} of the archive`, entry.name);
147
+ }
148
+ }
149
+ // Rule 4: the path of a link appears one time
150
+ const isLinkPath = links[0].has(keys[0]) || links[1].has(keys[1]);
151
+ if (isLinkPath && (entry.kind !== "symlink" || seenLinks.has(keys[1]))) {
152
+ throw new ArchiveError("UNSAFE_LINK", `The path ${entry.name} is a link and another entry of the archive`, entry.name);
153
+ }
154
+ if (entry.kind === "symlink") {
155
+ seenLinks.add(keys[1]);
156
+ // Rule 3: the target stays in the target folder
157
+ const linkTarget = entry.linkTarget ?? "";
158
+ if (linkTarget === "" || isAbsoluteName(linkTarget) || linkTarget.includes("\0")) {
159
+ throw new ArchiveError("UNSAFE_LINK", `The link ${entry.name} points to ${JSON.stringify(linkTarget)}: a link must point to a relative path`, entry.name);
160
+ }
161
+ for (const fold of [false, true]) {
162
+ const resolved = resolve([...entry.parts.slice(0, -1), ...linkParts(linkTarget)], links[fold ? 1 : 0], fold, foreignLink, { steps: MAX_LINK_STEPS });
163
+ if (resolved === undefined) {
164
+ throw new ArchiveError("UNSAFE_LINK", `The link ${entry.name} points to ${linkTarget}, out of the target folder`, entry.name);
165
+ }
166
+ }
167
+ }
168
+ if (entry.kind === "hardlink") {
169
+ // Rule 5: a hard link names an earlier file of the archive
170
+ const linked = entryParts(entry.linkTarget ?? "", "UNSAFE_LINK");
171
+ if (!files.has(keyOf(linked, true))) {
172
+ throw new ArchiveError("UNSAFE_LINK", `The hard link ${entry.name} names ${entry.linkTarget}, which is not an earlier file of the archive`, entry.name);
173
+ }
174
+ }
175
+ if (entry.kind === "file")
176
+ files.add(keys[1]);
177
+ // Rule 6: the folders of the target on the way are folders, not links
178
+ for (let length = 1; length < entry.parts.length; length++) {
179
+ const folder = join(target, ...entry.parts.slice(0, length));
180
+ const found = statOf(stats, folder);
181
+ if (found === undefined)
182
+ break;
183
+ if (found.isSymbolicLink())
184
+ throw new ArchiveError("UNSAFE_PATH", `The folder ${folder} of the target is a link: the entry ${entry.name} can go out through it`, entry.name);
185
+ if (!found.isDirectory())
186
+ throw new ArchiveError("EXISTS", `${folder} is a file, and the entry ${entry.name} needs a folder there`, entry.name);
187
+ }
188
+ // Rule 7: an existing path
189
+ const existing = statOf(stats, join(target, ...entry.parts));
190
+ if (existing !== undefined) {
191
+ if (entry.kind === "directory") {
192
+ if (!existing.isDirectory())
193
+ throw new ArchiveError("EXISTS", `${join(target, ...entry.parts)} exists and is not a folder`, entry.name);
194
+ }
195
+ else if (existing.isDirectory()) {
196
+ throw new ArchiveError("EXISTS", `${join(target, ...entry.parts)} is a folder, and the entry ${entry.name} is not`, entry.name);
197
+ }
198
+ else if (!options.overwrite) {
199
+ throw new ArchiveError("EXISTS", `${join(target, ...entry.parts)} exists: give overwrite: true to replace it`, entry.name);
200
+ }
201
+ }
202
+ }
203
+ return planned;
204
+ }
205
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * archive.create procedure
3
+ *
4
+ * Make a tar.gz, tar or zip archive of a folder or of files. The procedure writes a temporary
5
+ * file next to the archive, and renames it at the end: a failed call leaves no part of an
6
+ * archive. The walk does not follow a symbolic link: the archive gets the link.
7
+ */
8
+ import { type ArchiveSettings } from "../../format.js";
9
+ import type { ArchiveCreateInput, ArchiveCreateOutput } from "../../types.js";
10
+ /**
11
+ * Make a tar.gz or zip archive of a folder or of files
12
+ */
13
+ export declare function archiveCreate(input: ArchiveCreateInput, settings?: ArchiveSettings): Promise<ArchiveCreateOutput>;
14
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/procedures/archive/create.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAA0C,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAK/F,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAsB9E;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,EAAE,QAAQ,GAAE,eAA0C,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyCjJ"}