@procedures/archive 0.0.0-stage → 0.3.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/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +95 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/format.d.ts +25 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +60 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +34 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +148 -0
- package/dist/module.js.map +1 -0
- package/dist/paths.d.ts +58 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +205 -0
- package/dist/paths.js.map +1 -0
- package/dist/procedures/archive/create.d.ts +14 -0
- package/dist/procedures/archive/create.d.ts.map +1 -0
- package/dist/procedures/archive/create.js +81 -0
- package/dist/procedures/archive/create.js.map +1 -0
- package/dist/procedures/archive/extract.d.ts +17 -0
- package/dist/procedures/archive/extract.d.ts.map +1 -0
- package/dist/procedures/archive/extract.js +101 -0
- package/dist/procedures/archive/extract.js.map +1 -0
- package/dist/procedures/archive/index.d.ts +4 -0
- package/dist/procedures/archive/index.d.ts.map +1 -0
- package/dist/procedures/archive/index.js +4 -0
- package/dist/procedures/archive/index.js.map +1 -0
- package/dist/procedures/archive/list.d.ts +15 -0
- package/dist/procedures/archive/list.d.ts.map +1 -0
- package/dist/procedures/archive/list.js +47 -0
- package/dist/procedures/archive/list.js.map +1 -0
- package/dist/register.d.ts +6 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +8 -0
- package/dist/register.js.map +1 -0
- package/dist/tar.d.ts +38 -0
- package/dist/tar.d.ts.map +1 -0
- package/dist/tar.js +193 -0
- package/dist/tar.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/walk.d.ts +34 -0
- package/dist/walk.d.ts.map +1 -0
- package/dist/walk.js +67 -0
- package/dist/walk.js.map +1 -0
- package/dist/zip.d.ts +57 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +397 -0
- package/dist/zip.js.map +1 -0
- package/package.json +77 -3
- package/src/errors.ts +33 -0
- package/src/format.ts +64 -0
- package/src/index.ts +9 -0
- package/src/module.ts +192 -0
- package/src/paths.ts +230 -0
- package/src/procedures/archive/create.ts +84 -0
- package/src/procedures/archive/extract.ts +103 -0
- package/src/procedures/archive/index.ts +3 -0
- package/src/procedures/archive/list.ts +50 -0
- package/src/register.ts +10 -0
- package/src/tar.ts +198 -0
- package/src/types.ts +101 -0
- package/src/walk.ts +85 -0
- package/src/zip.ts +419 -0
package/dist/zip.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zip archives on `node:zlib` (roadmap R46).
|
|
3
|
+
*
|
|
4
|
+
* The package reads and writes zip itself, for two reasons. The reader needs the external
|
|
5
|
+
* attributes of each entry, to see a symbolic link, and a limit on the bytes of each entry
|
|
6
|
+
* against a zip bomb. A zip library that decodes in memory gives neither.
|
|
7
|
+
*
|
|
8
|
+
* - The reader takes the central directory: stored and deflated entries, UTF-8 names, and the
|
|
9
|
+
* zip64 fields. It refuses an encrypted entry, another method and an archive on more disks.
|
|
10
|
+
* - The extract streams each entry and stops when it gets more bytes than the entry declares.
|
|
11
|
+
* It examines the size and the CRC-32 of each entry.
|
|
12
|
+
* - The writer stores each file, or deflates it when that is smaller. It writes no zip64 fields:
|
|
13
|
+
* it refuses more than 65535 entries and an archive of 4 GiB or more.
|
|
14
|
+
*/
|
|
15
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
16
|
+
import { open } from "node:fs/promises";
|
|
17
|
+
import { Readable, Transform, Writable } from "node:stream";
|
|
18
|
+
import { pipeline } from "node:stream/promises";
|
|
19
|
+
import { createInflateRaw, deflateRawSync } from "node:zlib";
|
|
20
|
+
import { ArchiveError } from "./errors.js";
|
|
21
|
+
const SIG_LOCAL = 0x04034b50;
|
|
22
|
+
const SIG_CENTRAL = 0x02014b50;
|
|
23
|
+
const SIG_END = 0x06054b50;
|
|
24
|
+
const SIG_END64 = 0x06064b50;
|
|
25
|
+
const SIG_LOCATOR64 = 0x07064b50;
|
|
26
|
+
const FLAG_ENCRYPTED = 0x0001;
|
|
27
|
+
const FLAG_UTF8 = 0x0800;
|
|
28
|
+
const METHOD_STORE = 0;
|
|
29
|
+
const METHOD_DEFLATE = 8;
|
|
30
|
+
const OS_UNIX = 3;
|
|
31
|
+
const S_IFMT = 0o170000;
|
|
32
|
+
const S_IFLNK = 0o120000;
|
|
33
|
+
const S_IFDIR = 0o040000;
|
|
34
|
+
const S_IFREG = 0o100000;
|
|
35
|
+
/** The largest central directory that the reader takes. */
|
|
36
|
+
const MAX_DIRECTORY_BYTES = 256 * 1024 * 1024;
|
|
37
|
+
/** The largest target of a symbolic link. */
|
|
38
|
+
const MAX_LINK_BYTES = 4096;
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// CRC-32
|
|
41
|
+
// =============================================================================
|
|
42
|
+
const CRC_TABLE = (() => {
|
|
43
|
+
const table = new Uint32Array(256);
|
|
44
|
+
for (let n = 0; n < 256; n++) {
|
|
45
|
+
let c = n;
|
|
46
|
+
for (let k = 0; k < 8; k++)
|
|
47
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
48
|
+
table[n] = c >>> 0;
|
|
49
|
+
}
|
|
50
|
+
return table;
|
|
51
|
+
})();
|
|
52
|
+
/** The CRC-32 of bytes, continued from `crc` (0 for new bytes). */
|
|
53
|
+
export function crc32(bytes, crc = 0) {
|
|
54
|
+
let c = ~crc >>> 0;
|
|
55
|
+
for (let i = 0; i < bytes.length; i++)
|
|
56
|
+
c = CRC_TABLE[(c ^ bytes[i]) & 0xff] ^ (c >>> 8);
|
|
57
|
+
return ~c >>> 0;
|
|
58
|
+
}
|
|
59
|
+
/** The time of a DOS date and time, as a local time. */
|
|
60
|
+
function dosTime(date, time) {
|
|
61
|
+
return new Date(1980 + (date >> 9), ((date >> 5) & 15) - 1, date & 31, time >> 11, (time >> 5) & 63, (time & 31) * 2);
|
|
62
|
+
}
|
|
63
|
+
/** The DOS date and time of a time. */
|
|
64
|
+
function toDosTime(when) {
|
|
65
|
+
const year = Math.min(Math.max(when.getFullYear(), 1980), 2107);
|
|
66
|
+
return {
|
|
67
|
+
date: ((year - 1980) << 9) | ((when.getMonth() + 1) << 5) | when.getDate(),
|
|
68
|
+
time: (when.getHours() << 11) | (when.getMinutes() << 5) | Math.floor(when.getSeconds() / 2),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const utf8 = new TextDecoder("utf-8", { fatal: true });
|
|
72
|
+
/** The text of a name: UTF-8 when the bytes are UTF-8, else Latin-1. */
|
|
73
|
+
function decodeName(bytes, flags) {
|
|
74
|
+
if (flags & FLAG_UTF8)
|
|
75
|
+
return bytes.toString("utf8");
|
|
76
|
+
try {
|
|
77
|
+
return utf8.decode(bytes);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return bytes.toString("latin1");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** A 64-bit number that must fit in a safe integer. */
|
|
84
|
+
function u64(buffer, offset) {
|
|
85
|
+
const value = buffer.readBigUInt64LE(offset);
|
|
86
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER))
|
|
87
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip has a size or an offset that is too large");
|
|
88
|
+
return Number(value);
|
|
89
|
+
}
|
|
90
|
+
async function readAt(handle, offset, length) {
|
|
91
|
+
const buffer = Buffer.alloc(length);
|
|
92
|
+
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
93
|
+
if (bytesRead !== length)
|
|
94
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip ends before its central directory ends");
|
|
95
|
+
return buffer;
|
|
96
|
+
}
|
|
97
|
+
/** The place and the size of the central directory, and the number of entries. */
|
|
98
|
+
async function findDirectory(handle, fileSize) {
|
|
99
|
+
const tailLength = Math.min(fileSize, 22 + 65_535);
|
|
100
|
+
const tail = await readAt(handle, fileSize - tailLength, tailLength);
|
|
101
|
+
let at = -1;
|
|
102
|
+
for (let i = tail.length - 22; i >= 0; i--) {
|
|
103
|
+
if (tail.readUInt32LE(i) === SIG_END) {
|
|
104
|
+
at = i;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (at < 0)
|
|
109
|
+
throw new ArchiveError("BAD_ARCHIVE", "The file has no end of a zip central directory");
|
|
110
|
+
if (tail.readUInt16LE(at + 4) !== 0 || tail.readUInt16LE(at + 6) !== 0)
|
|
111
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip is on more than one disk");
|
|
112
|
+
let count = tail.readUInt16LE(at + 10);
|
|
113
|
+
let size = tail.readUInt32LE(at + 12);
|
|
114
|
+
let offset = tail.readUInt32LE(at + 16);
|
|
115
|
+
if (count === 0xffff || size === 0xffffffff || offset === 0xffffffff) {
|
|
116
|
+
const locatorAt = fileSize - tailLength + at - 20;
|
|
117
|
+
if (locatorAt < 0)
|
|
118
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip64 locator is missing");
|
|
119
|
+
const locator = await readAt(handle, locatorAt, 20);
|
|
120
|
+
if (locator.readUInt32LE(0) !== SIG_LOCATOR64)
|
|
121
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip64 locator is missing");
|
|
122
|
+
const end64 = await readAt(handle, u64(locator, 8), 56);
|
|
123
|
+
if (end64.readUInt32LE(0) !== SIG_END64)
|
|
124
|
+
throw new ArchiveError("BAD_ARCHIVE", "The zip64 end of the central directory is missing");
|
|
125
|
+
count = u64(end64, 32);
|
|
126
|
+
size = u64(end64, 40);
|
|
127
|
+
offset = u64(end64, 48);
|
|
128
|
+
}
|
|
129
|
+
if (offset + size > fileSize)
|
|
130
|
+
throw new ArchiveError("BAD_ARCHIVE", "The central directory of the zip is out of the file");
|
|
131
|
+
if (size > MAX_DIRECTORY_BYTES)
|
|
132
|
+
throw new ArchiveError("TOO_LARGE", "The central directory of the zip is too large");
|
|
133
|
+
return { offset, size, count };
|
|
134
|
+
}
|
|
135
|
+
/** The kind of an entry: from the Unix type of its attributes, from a name with `/`, or from the DOS folder flag. */
|
|
136
|
+
function kindOf(name, madeBy, external) {
|
|
137
|
+
const unixType = madeBy >> 8 === OS_UNIX ? (external >>> 16) & S_IFMT : 0;
|
|
138
|
+
if (unixType === S_IFLNK)
|
|
139
|
+
return "symlink";
|
|
140
|
+
if (unixType === S_IFDIR || name.endsWith("/") || name.endsWith("\\") || (external & 0x10) !== 0)
|
|
141
|
+
return "directory";
|
|
142
|
+
return "file";
|
|
143
|
+
}
|
|
144
|
+
/** This function reads the central directory of a zip. It throws `TOO_LARGE` for more than `maxEntries` entries. */
|
|
145
|
+
export async function readZipDirectory(path, maxEntries) {
|
|
146
|
+
const handle = await open(path, "r");
|
|
147
|
+
try {
|
|
148
|
+
const { size: fileSize } = await handle.stat();
|
|
149
|
+
const directory = await findDirectory(handle, fileSize);
|
|
150
|
+
if (directory.count > maxEntries)
|
|
151
|
+
throw new ArchiveError("TOO_LARGE", `The archive has ${directory.count} entries, more than the limit of ${maxEntries}`);
|
|
152
|
+
const buffer = await readAt(handle, directory.offset, directory.size);
|
|
153
|
+
const entries = [];
|
|
154
|
+
let at = 0;
|
|
155
|
+
for (let index = 0; index < directory.count; index++) {
|
|
156
|
+
if (at + 46 > buffer.length || buffer.readUInt32LE(at) !== SIG_CENTRAL)
|
|
157
|
+
throw new ArchiveError("BAD_ARCHIVE", "The central directory of the zip is damaged");
|
|
158
|
+
const madeBy = buffer.readUInt16LE(at + 4);
|
|
159
|
+
const flags = buffer.readUInt16LE(at + 8);
|
|
160
|
+
const method = buffer.readUInt16LE(at + 10);
|
|
161
|
+
const time = buffer.readUInt16LE(at + 12);
|
|
162
|
+
const date = buffer.readUInt16LE(at + 14);
|
|
163
|
+
const crc = buffer.readUInt32LE(at + 16);
|
|
164
|
+
let compressedSize = buffer.readUInt32LE(at + 20);
|
|
165
|
+
let size = buffer.readUInt32LE(at + 24);
|
|
166
|
+
const nameLength = buffer.readUInt16LE(at + 28);
|
|
167
|
+
const extraLength = buffer.readUInt16LE(at + 30);
|
|
168
|
+
const commentLength = buffer.readUInt16LE(at + 32);
|
|
169
|
+
const external = buffer.readUInt32LE(at + 38);
|
|
170
|
+
let localOffset = buffer.readUInt32LE(at + 42);
|
|
171
|
+
const nameStart = at + 46;
|
|
172
|
+
const extraStart = nameStart + nameLength;
|
|
173
|
+
const next = extraStart + extraLength + commentLength;
|
|
174
|
+
if (next > buffer.length)
|
|
175
|
+
throw new ArchiveError("BAD_ARCHIVE", "The central directory of the zip is damaged");
|
|
176
|
+
const name = decodeName(buffer.subarray(nameStart, extraStart), flags);
|
|
177
|
+
// The zip64 field has the values that do not fit in 32 bits, in this order
|
|
178
|
+
if (size === 0xffffffff || compressedSize === 0xffffffff || localOffset === 0xffffffff) {
|
|
179
|
+
let field = extraStart;
|
|
180
|
+
let found = false;
|
|
181
|
+
while (field + 4 <= extraStart + extraLength) {
|
|
182
|
+
const id = buffer.readUInt16LE(field);
|
|
183
|
+
const length = buffer.readUInt16LE(field + 2);
|
|
184
|
+
if (id === 0x0001) {
|
|
185
|
+
let value = field + 4;
|
|
186
|
+
const end = value + length;
|
|
187
|
+
const take = () => {
|
|
188
|
+
if (value + 8 > end)
|
|
189
|
+
throw new ArchiveError("BAD_ARCHIVE", `The zip64 field of ${name} is too short`, name);
|
|
190
|
+
const result = u64(buffer, value);
|
|
191
|
+
value += 8;
|
|
192
|
+
return result;
|
|
193
|
+
};
|
|
194
|
+
if (size === 0xffffffff)
|
|
195
|
+
size = take();
|
|
196
|
+
if (compressedSize === 0xffffffff)
|
|
197
|
+
compressedSize = take();
|
|
198
|
+
if (localOffset === 0xffffffff)
|
|
199
|
+
localOffset = take();
|
|
200
|
+
found = true;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
field += 4 + length;
|
|
204
|
+
}
|
|
205
|
+
if (!found)
|
|
206
|
+
throw new ArchiveError("BAD_ARCHIVE", `The entry ${name} has no zip64 field`, name);
|
|
207
|
+
}
|
|
208
|
+
const unixMode = madeBy >> 8 === OS_UNIX ? (external >>> 16) & 0o7777 : 0;
|
|
209
|
+
entries.push({
|
|
210
|
+
name,
|
|
211
|
+
kind: kindOf(name, madeBy, external),
|
|
212
|
+
method,
|
|
213
|
+
flags,
|
|
214
|
+
crc,
|
|
215
|
+
compressedSize,
|
|
216
|
+
size,
|
|
217
|
+
localOffset,
|
|
218
|
+
mode: unixMode === 0 ? undefined : unixMode,
|
|
219
|
+
mtime: dosTime(date, time),
|
|
220
|
+
});
|
|
221
|
+
at = next;
|
|
222
|
+
}
|
|
223
|
+
return entries;
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
await handle.close();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** The offset of the data of an entry: after its local header. */
|
|
230
|
+
async function localDataOffset(archive, entry) {
|
|
231
|
+
const handle = await open(archive, "r");
|
|
232
|
+
try {
|
|
233
|
+
const header = await readAt(handle, entry.localOffset, 30);
|
|
234
|
+
if (header.readUInt32LE(0) !== SIG_LOCAL)
|
|
235
|
+
throw new ArchiveError("BAD_ARCHIVE", `The local header of ${entry.name} is damaged`, entry.name);
|
|
236
|
+
return entry.localOffset + 30 + header.readUInt16LE(26) + header.readUInt16LE(28);
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
await handle.close();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** This function refuses an entry that the reader does not decode. */
|
|
243
|
+
function assertReadable(entry) {
|
|
244
|
+
if (entry.flags & FLAG_ENCRYPTED)
|
|
245
|
+
throw new ArchiveError("BAD_ARCHIVE", `The entry ${entry.name} is encrypted`, entry.name);
|
|
246
|
+
if (entry.method !== METHOD_STORE && entry.method !== METHOD_DEFLATE) {
|
|
247
|
+
throw new ArchiveError("BAD_ARCHIVE", `The entry ${entry.name} uses the compression method ${entry.method}: only store and deflate are supported`, entry.name);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** A stream step that counts the bytes and the CRC-32, and stops at more bytes than the entry declares. */
|
|
251
|
+
class EntryCheck extends Transform {
|
|
252
|
+
entry;
|
|
253
|
+
bytes = 0;
|
|
254
|
+
crc = 0;
|
|
255
|
+
constructor(entry) {
|
|
256
|
+
super();
|
|
257
|
+
this.entry = entry;
|
|
258
|
+
}
|
|
259
|
+
_transform(chunk, _encoding, done) {
|
|
260
|
+
this.bytes += chunk.length;
|
|
261
|
+
if (this.bytes > this.entry.size) {
|
|
262
|
+
done(new ArchiveError("BAD_ARCHIVE", `The entry ${this.entry.name} has more bytes than its declared size of ${this.entry.size}`, this.entry.name));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this.crc = crc32(chunk, this.crc);
|
|
266
|
+
done(null, chunk);
|
|
267
|
+
}
|
|
268
|
+
_flush(done) {
|
|
269
|
+
if (this.bytes !== this.entry.size) {
|
|
270
|
+
done(new ArchiveError("BAD_ARCHIVE", `The entry ${this.entry.name} has ${this.bytes} bytes, not ${this.entry.size}`, this.entry.name));
|
|
271
|
+
}
|
|
272
|
+
else if (this.crc !== this.entry.crc) {
|
|
273
|
+
done(new ArchiveError("BAD_ARCHIVE", `The CRC-32 of the entry ${this.entry.name} is not correct`, this.entry.name));
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
done();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The decoded bytes of an entry, through the checks, into the stream of `open`. The stream opens
|
|
282
|
+
* after the checks of the entry and of its local header: a refused entry makes no file.
|
|
283
|
+
*/
|
|
284
|
+
async function decodeEntry(archive, entry, open) {
|
|
285
|
+
assertReadable(entry);
|
|
286
|
+
const start = await localDataOffset(archive, entry);
|
|
287
|
+
const destination = open();
|
|
288
|
+
if (entry.compressedSize === 0) {
|
|
289
|
+
await pipeline(Readable.from([]), new EntryCheck(entry), destination);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const input = createReadStream(archive, { start, end: start + entry.compressedSize - 1 });
|
|
293
|
+
if (entry.method === METHOD_DEFLATE) {
|
|
294
|
+
await pipeline(input, createInflateRaw(), new EntryCheck(entry), destination);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
await pipeline(input, new EntryCheck(entry), destination);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* This function writes the content of a file entry to `destination`, with the checks. The file
|
|
302
|
+
* must not exist: the caller removes an old file first, so the write never follows a link.
|
|
303
|
+
*/
|
|
304
|
+
export async function extractZipFile(archive, entry, destination, mode) {
|
|
305
|
+
await decodeEntry(archive, entry, () => createWriteStream(destination, { flags: "wx", ...(mode !== undefined ? { mode } : {}) }));
|
|
306
|
+
}
|
|
307
|
+
/** This function gives the target of a symbolic link entry: its content, as text. */
|
|
308
|
+
export async function readZipLink(archive, entry) {
|
|
309
|
+
if (entry.size > MAX_LINK_BYTES)
|
|
310
|
+
throw new ArchiveError("BAD_ARCHIVE", `The link ${entry.name} has a target of more than ${MAX_LINK_BYTES} bytes`, entry.name);
|
|
311
|
+
const chunks = [];
|
|
312
|
+
const collect = new Writable({
|
|
313
|
+
write(chunk, _encoding, done) {
|
|
314
|
+
chunks.push(chunk);
|
|
315
|
+
done();
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
await decodeEntry(archive, entry, () => collect);
|
|
319
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* This function writes a zip to an open file. The names are not examined here: `archive.create`
|
|
323
|
+
* gives only the relative paths of a walk, and a test gives hostile names on purpose.
|
|
324
|
+
*/
|
|
325
|
+
export async function writeZip(handle, entries) {
|
|
326
|
+
if (entries.length > 0xffff)
|
|
327
|
+
throw new ArchiveError("TOO_LARGE", "A zip without zip64 has at most 65535 entries");
|
|
328
|
+
const central = [];
|
|
329
|
+
let offset = 0;
|
|
330
|
+
const write = async (buffer) => {
|
|
331
|
+
if (offset + buffer.length >= 0xffffffff)
|
|
332
|
+
throw new ArchiveError("TOO_LARGE", "A zip without zip64 must be smaller than 4 GiB");
|
|
333
|
+
await handle.write(buffer, 0, buffer.length, offset);
|
|
334
|
+
offset += buffer.length;
|
|
335
|
+
};
|
|
336
|
+
for (const entry of entries) {
|
|
337
|
+
const name = Buffer.from(entry.kind === "directory" && !entry.name.endsWith("/") ? `${entry.name}/` : entry.name, "utf8");
|
|
338
|
+
const raw = Buffer.from(typeof entry.data === "function" ? await entry.data() : (entry.data ?? new Uint8Array(0)));
|
|
339
|
+
const crc = crc32(raw);
|
|
340
|
+
let method = METHOD_STORE;
|
|
341
|
+
let stored = raw;
|
|
342
|
+
if (entry.kind === "file" && raw.length > 0) {
|
|
343
|
+
const deflated = deflateRawSync(raw);
|
|
344
|
+
if (deflated.length < raw.length) {
|
|
345
|
+
method = METHOD_DEFLATE;
|
|
346
|
+
stored = deflated;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const { date, time } = toDosTime(entry.mtime ?? new Date());
|
|
350
|
+
const type = entry.kind === "symlink" ? S_IFLNK : entry.kind === "directory" ? S_IFDIR : S_IFREG;
|
|
351
|
+
const mode = entry.mode ?? (entry.kind === "directory" ? 0o755 : entry.kind === "symlink" ? 0o777 : 0o644);
|
|
352
|
+
const external = (((type | (mode & 0o7777)) << 16) | (entry.kind === "directory" ? 0x10 : 0)) >>> 0;
|
|
353
|
+
const local = Buffer.alloc(30);
|
|
354
|
+
local.writeUInt32LE(SIG_LOCAL, 0);
|
|
355
|
+
local.writeUInt16LE(20, 4);
|
|
356
|
+
local.writeUInt16LE(FLAG_UTF8, 6);
|
|
357
|
+
local.writeUInt16LE(method, 8);
|
|
358
|
+
local.writeUInt16LE(time, 10);
|
|
359
|
+
local.writeUInt16LE(date, 12);
|
|
360
|
+
local.writeUInt32LE(crc, 14);
|
|
361
|
+
local.writeUInt32LE(stored.length, 18);
|
|
362
|
+
local.writeUInt32LE(raw.length, 22);
|
|
363
|
+
local.writeUInt16LE(name.length, 26);
|
|
364
|
+
local.writeUInt16LE(0, 28);
|
|
365
|
+
const localOffset = offset;
|
|
366
|
+
await write(Buffer.concat([local, name]));
|
|
367
|
+
if (stored.length > 0)
|
|
368
|
+
await write(stored);
|
|
369
|
+
const record = Buffer.alloc(46);
|
|
370
|
+
record.writeUInt32LE(SIG_CENTRAL, 0);
|
|
371
|
+
record.writeUInt16LE((OS_UNIX << 8) | 20, 4);
|
|
372
|
+
record.writeUInt16LE(20, 6);
|
|
373
|
+
record.writeUInt16LE(FLAG_UTF8, 8);
|
|
374
|
+
record.writeUInt16LE(method, 10);
|
|
375
|
+
record.writeUInt16LE(time, 12);
|
|
376
|
+
record.writeUInt16LE(date, 14);
|
|
377
|
+
record.writeUInt32LE(crc, 16);
|
|
378
|
+
record.writeUInt32LE(stored.length, 20);
|
|
379
|
+
record.writeUInt32LE(raw.length, 24);
|
|
380
|
+
record.writeUInt16LE(name.length, 28);
|
|
381
|
+
record.writeUInt32LE(external, 38);
|
|
382
|
+
record.writeUInt32LE(localOffset, 42);
|
|
383
|
+
central.push(record, name);
|
|
384
|
+
}
|
|
385
|
+
const directory = Buffer.concat(central);
|
|
386
|
+
const directoryOffset = offset;
|
|
387
|
+
await write(directory);
|
|
388
|
+
const end = Buffer.alloc(22);
|
|
389
|
+
end.writeUInt32LE(SIG_END, 0);
|
|
390
|
+
end.writeUInt16LE(entries.length, 8);
|
|
391
|
+
end.writeUInt16LE(entries.length, 10);
|
|
392
|
+
end.writeUInt32LE(directory.length, 12);
|
|
393
|
+
end.writeUInt32LE(directoryOffset, 16);
|
|
394
|
+
await write(end);
|
|
395
|
+
return offset;
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=zip.js.map
|
package/dist/zip.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.js","sourceRoot":"","sources":["../src/zip.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,80 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package",
|
|
2
3
|
"name": "@procedures/archive",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
4
|
+
"version": "0.3.0",
|
|
5
|
+
"description": "Archives as procedures: make, list and extract tar.gz and zip, with a check of each path against zip slip and links out of the target.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"procedures",
|
|
8
|
+
"archive",
|
|
9
|
+
"tar",
|
|
10
|
+
"zip",
|
|
11
|
+
"gzip",
|
|
12
|
+
"zip-slip"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://mark1russell7.github.io/client/",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/mark1russell7/client/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/mark1russell7/client.git",
|
|
21
|
+
"directory": "packages/archive"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Mark Russell (https://github.com/mark1russell7)",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./module": {
|
|
34
|
+
"types": "./dist/module.d.ts",
|
|
35
|
+
"import": "./dist/module.js"
|
|
36
|
+
},
|
|
37
|
+
"./register": {
|
|
38
|
+
"types": "./dist/register.d.ts",
|
|
39
|
+
"import": "./dist/register.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"src",
|
|
45
|
+
"!src/**/*.test.ts",
|
|
46
|
+
"!src/**/*.test.tsx",
|
|
47
|
+
"!src/**/__tests__",
|
|
48
|
+
"CHANGELOG.md"
|
|
49
|
+
],
|
|
50
|
+
"sideEffects": [
|
|
51
|
+
"./dist/register.js"
|
|
52
|
+
],
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@mark1russell7/cue": "^1.0.0",
|
|
55
|
+
"typescript": "^7.0.2",
|
|
56
|
+
"vitest": "^5.0.3"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=22"
|
|
60
|
+
},
|
|
61
|
+
"client": {
|
|
62
|
+
"procedures": "./dist/register.js"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@procedures/client": "0.3.0",
|
|
66
|
+
"tar": "^7.5.0",
|
|
67
|
+
"zod": "^4.6.5"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public",
|
|
71
|
+
"provenance": true
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "tsc -b",
|
|
75
|
+
"typecheck": "tsc --noEmit",
|
|
76
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
77
|
+
"test": "vitest run",
|
|
78
|
+
"test:watch": "vitest"
|
|
79
|
+
}
|
|
6
80
|
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The errors of the archive procedures.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** The reason of an `ArchiveError`. */
|
|
6
|
+
export type ArchiveErrorCode =
|
|
7
|
+
/** The format is not known, or it is not the format of the file. */
|
|
8
|
+
| "BAD_FORMAT"
|
|
9
|
+
/** The archive is damaged, or it uses a feature that the package does not read. */
|
|
10
|
+
| "BAD_ARCHIVE"
|
|
11
|
+
/** A path exists already: the archive of `create`, or a file of `extract` without `overwrite`. */
|
|
12
|
+
| "EXISTS"
|
|
13
|
+
/** A path of the input or an entry of the archive is not safe: `..`, an absolute path, or a way through a link. */
|
|
14
|
+
| "UNSAFE_PATH"
|
|
15
|
+
/** A link of the archive goes out of the target folder, or a hard link names no file of the archive. */
|
|
16
|
+
| "UNSAFE_LINK"
|
|
17
|
+
/** The archive has an entry that the package does not extract: a device, a FIFO or another special file. */
|
|
18
|
+
| "UNSUPPORTED_ENTRY"
|
|
19
|
+
/** The archive has more entries or more bytes than the limits of the module. */
|
|
20
|
+
| "TOO_LARGE";
|
|
21
|
+
|
|
22
|
+
/** An error of an archive procedure. `entry` names the entry of the archive, when one is the cause. */
|
|
23
|
+
export class ArchiveError extends Error {
|
|
24
|
+
override readonly name = "ArchiveError";
|
|
25
|
+
readonly code: ArchiveErrorCode;
|
|
26
|
+
readonly entry: string | undefined;
|
|
27
|
+
|
|
28
|
+
constructor(code: ArchiveErrorCode, message: string, entry?: string) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.entry = entry;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/format.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
|
|
6
|
+
import { open } from "node:fs/promises";
|
|
7
|
+
import { ArchiveError } from "./errors.js";
|
|
8
|
+
import type { ArchiveFormat } from "./types.js";
|
|
9
|
+
|
|
10
|
+
/** The limits of the procedures of a module. */
|
|
11
|
+
export interface ArchiveSettings {
|
|
12
|
+
/** The most bytes of the files of one archive: `extract` and `create` refuse more. */
|
|
13
|
+
readonly maxBytes: number;
|
|
14
|
+
/** The most entries of one archive. */
|
|
15
|
+
readonly maxEntries: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The default most bytes: 1 GiB. */
|
|
19
|
+
export const DEFAULT_MAX_BYTES: number = 1024 * 1024 * 1024;
|
|
20
|
+
/** The default most entries. */
|
|
21
|
+
export const DEFAULT_MAX_ENTRIES = 100_000;
|
|
22
|
+
|
|
23
|
+
/** The settings of the default module. */
|
|
24
|
+
export const DEFAULT_ARCHIVE_SETTINGS: ArchiveSettings = Object.freeze({ maxBytes: DEFAULT_MAX_BYTES, maxEntries: DEFAULT_MAX_ENTRIES });
|
|
25
|
+
|
|
26
|
+
/** The format of a new archive from its name, or the format of the input. */
|
|
27
|
+
export function formatOfName(path: string, given: ArchiveFormat | undefined): ArchiveFormat {
|
|
28
|
+
if (given !== undefined) return given;
|
|
29
|
+
const name = path.toLowerCase();
|
|
30
|
+
if (name.endsWith(".tar.gz") || name.endsWith(".tgz")) return "tar.gz";
|
|
31
|
+
if (name.endsWith(".tar")) return "tar";
|
|
32
|
+
if (name.endsWith(".zip")) return "zip";
|
|
33
|
+
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`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The format that the first bytes of a file show, or undefined. */
|
|
37
|
+
export async function sniffFormat(path: string): Promise<ArchiveFormat | undefined> {
|
|
38
|
+
const handle = await open(path, "r");
|
|
39
|
+
try {
|
|
40
|
+
const head = Buffer.alloc(512);
|
|
41
|
+
const { bytesRead } = await handle.read(head, 0, 512, 0);
|
|
42
|
+
if (bytesRead >= 2 && head[0] === 0x1f && head[1] === 0x8b) return "tar.gz";
|
|
43
|
+
if (bytesRead >= 4 && head[0] === 0x50 && head[1] === 0x4b && ((head[2] === 3 && head[3] === 4) || (head[2] === 5 && head[3] === 6))) return "zip";
|
|
44
|
+
if (bytesRead >= 262 && head.toString("latin1", 257, 262) === "ustar") return "tar";
|
|
45
|
+
// An empty tar: zero blocks without a header
|
|
46
|
+
if (bytesRead === 512 && head.every((byte) => byte === 0)) return "tar";
|
|
47
|
+
return undefined;
|
|
48
|
+
} finally {
|
|
49
|
+
await handle.close();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The format of an existing archive: its first bytes, which must agree with the format of the input. */
|
|
54
|
+
export async function formatOfFile(path: string, given: ArchiveFormat | undefined): Promise<ArchiveFormat> {
|
|
55
|
+
const found = await sniffFormat(path);
|
|
56
|
+
if (found === undefined) {
|
|
57
|
+
if (given === "tar") return "tar";
|
|
58
|
+
throw new ArchiveError("BAD_FORMAT", `${path} is not a tar.gz, tar or zip archive`);
|
|
59
|
+
}
|
|
60
|
+
if (given !== undefined && given !== found) {
|
|
61
|
+
throw new ArchiveError("BAD_FORMAT", `${path} is a ${found} archive, not a ${given} archive`);
|
|
62
|
+
}
|
|
63
|
+
return found;
|
|
64
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
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, type ArchiveErrorCode } from "./errors.js";
|
|
7
|
+
export { DEFAULT_ARCHIVE_SETTINGS, DEFAULT_MAX_BYTES, DEFAULT_MAX_ENTRIES, formatOfFile, formatOfName, sniffFormat, type ArchiveSettings } from "./format.js";
|
|
8
|
+
export { entryParts, isAbsoluteName, planExtract, type PlanOptions, type PlannedEntry, type RawEntry } from "./paths.js";
|
|
9
|
+
export { crc32, readZipDirectory, writeZip, type ZipEntry, type ZipWriteEntry } from "./zip.js";
|