modern-tar 0.5.2 → 0.5.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 (2) hide show
  1. package/dist/fs/index.js +37 -48
  2. package/package.json +1 -1
package/dist/fs/index.js CHANGED
@@ -6,6 +6,42 @@ import { PassThrough, Readable, Writable } from "node:stream";
6
6
  import { createWriteStream } from "node:fs";
7
7
  import { pipeline } from "node:stream/promises";
8
8
 
9
+ //#region src/fs/path.ts
10
+ const unicodeCache = /* @__PURE__ */ new Map();
11
+ const normalizeUnicode = (s) => {
12
+ let result = unicodeCache.get(s);
13
+ if (result !== void 0) unicodeCache.delete(s);
14
+ result = result ?? s.normalize("NFD");
15
+ unicodeCache.set(s, result);
16
+ if (unicodeCache.size > 1e4) unicodeCache.delete(unicodeCache.keys().next().value);
17
+ return result;
18
+ };
19
+ function validateBounds(targetPath, destDir, errorMessage) {
20
+ const target = normalizeUnicode(path.resolve(targetPath));
21
+ const dest = path.resolve(destDir);
22
+ if (target !== dest && !target.startsWith(dest + path.sep)) throw new Error(errorMessage);
23
+ }
24
+ const win32Reserved = {
25
+ ":": "",
26
+ "<": "",
27
+ ">": "",
28
+ "|": "",
29
+ "?": "",
30
+ "*": "",
31
+ "\"": ""
32
+ };
33
+ function normalizeName(name) {
34
+ const path$1 = name.replace(/\\/g, "/");
35
+ if (path$1.split("/").includes("..") || /^[a-zA-Z]:\.\./.test(path$1)) throw new Error(`${name} points outside extraction directory`);
36
+ let relative = path$1;
37
+ if (/^[a-zA-Z]:/.test(relative)) relative = relative.replace(/^[a-zA-Z]:[/\\]?/, "");
38
+ else if (relative.startsWith("/")) relative = relative.replace(/^\/+/, "");
39
+ if (process.platform === "win32") return relative.replace(/[<>:"|?*]/g, (char) => win32Reserved[char]);
40
+ return relative;
41
+ }
42
+ const normalizeHeaderName = (s) => normalizeUnicode(normalizeName(s.replace(/\/+$/, "")));
43
+
44
+ //#endregion
9
45
  //#region src/fs/pack.ts
10
46
  const packTarSources = packTar;
11
47
  function packTar(sources, options = {}) {
@@ -96,7 +132,7 @@ function packTar(sources, options = {}) {
96
132
  };
97
133
  const processJob = async (job, index) => {
98
134
  let jobResult = null;
99
- const target = job.target.replace(/\\/g, "/");
135
+ const target = normalizeName(job.target);
100
136
  try {
101
137
  if (job.type === "content" || job.type === "stream") {
102
138
  let body$1;
@@ -206,52 +242,6 @@ function packTar(sources, options = {}) {
206
242
  return stream;
207
243
  }
208
244
 
209
- //#endregion
210
- //#region src/fs/win-path.ts
211
- const REPLACEMENTS = {
212
- ":": "",
213
- "<": "",
214
- ">": "",
215
- "|": "",
216
- "?": "",
217
- "*": "",
218
- "\"": ""
219
- };
220
- function normalizeWindowsPath(p) {
221
- if (!(process.platform === "win32")) return p;
222
- const normalized = p.replace(/\\/g, "/");
223
- if (/^[A-Za-z]:\.\./i.test(normalized)) throw new Error(`Entry ${p} points outside extraction directory.`);
224
- return normalized.replace(/^[A-Za-z]:/, "").replace(/[<>:"|?*]/g, (char) => REPLACEMENTS[char]);
225
- }
226
-
227
- //#endregion
228
- //#region src/fs/path.ts
229
- const unicodeCache = /* @__PURE__ */ new Map();
230
- const normalizeUnicode = (s) => {
231
- let result = unicodeCache.get(s);
232
- if (result !== void 0) unicodeCache.delete(s);
233
- result = result ?? s.normalize("NFD");
234
- unicodeCache.set(s, result);
235
- if (unicodeCache.size > 1e4) unicodeCache.delete(unicodeCache.keys().next().value);
236
- return result;
237
- };
238
- function stripTrailingSlashes(p) {
239
- let i = p.length - 1;
240
- if (i === -1 || p[i] !== "/") return p;
241
- let slashesStart = i;
242
- while (i > -1 && p[i] === "/") {
243
- slashesStart = i;
244
- i--;
245
- }
246
- return p.slice(0, slashesStart);
247
- }
248
- const normalizeHeaderName = (s) => normalizeUnicode(normalizeWindowsPath(stripTrailingSlashes(s)));
249
- function validateBounds(targetPath, destDir, errorMessage) {
250
- const target = normalizeUnicode(path.resolve(targetPath));
251
- const dest = path.resolve(destDir);
252
- if (target !== dest && !target.startsWith(dest + path.sep)) throw new Error(errorMessage);
253
- }
254
-
255
245
  //#endregion
256
246
  //#region src/fs/unpack.ts
257
247
  function unpackTar(directoryPath, options = {}) {
@@ -389,7 +379,6 @@ function createFSHandler(directoryPath, options) {
389
379
  try {
390
380
  const destDir = await destDirPromise;
391
381
  if (maxDepth !== Infinity && name.split("/").length > maxDepth) throw new Error("Tar exceeds max specified depth.");
392
- if (path.isAbsolute(name)) throw new Error(`Absolute path found in "${transformed.name}".`);
393
382
  const outPath = path.join(destDir.symbolic, name);
394
383
  validateBounds(outPath, destDir.symbolic, `Entry "${transformed.name}" points outside the extraction directory.`);
395
384
  const parentDir = path.dirname(outPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modern-tar",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Zero dependency streaming tar parser and writer for JavaScript.",
5
5
  "author": "Ayuhito <hello@ayuhito.com>",
6
6
  "license": "MIT",