Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@vltpkg/tar

Package Overview
Dependencies
Maintainers
6
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vltpkg/tar - npm Package Compare versions

Comparing version
1.0.0-rc.9
to
1.0.0-rc.10
+1
-1
dist/esm/unpack.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"unpack.d.ts","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,MAAM,YACR,MAAM,UACP,MAAM,KACb,OAAO,CAAC,IAAI,CAMd,CAAA"}
{"version":3,"file":"unpack.d.ts","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"AAwFA,eAAO,MAAM,MAAM,YACR,MAAM,UACP,MAAM,KACb,OAAO,CAAC,IAAI,CAMd,CAAA"}
import { error } from '@vltpkg/error-cause';
import { randomBytes } from 'node:crypto';
import { lstat, mkdir, rename, writeFile } from 'node:fs/promises';
import { basename, dirname, parse, resolve } from 'node:path';
import { basename, dirname, resolve, sep } from 'node:path';
import { rimraf } from 'rimraf';

@@ -25,3 +25,3 @@ import { Header } from 'tar/header';

const tmpSuffix = () => tmp + String(id++);
const checkFs = (h, tarDir) => {
const checkFs = (h, tarDir, target) => {
/* c8 ignore start - impossible */

@@ -34,12 +34,11 @@ if (!h.path)

h.path = h.path.replace(/[\\/]+/g, '/');
const parsed = parse(h.path);
if (parsed.root)
// packages should always be in a 'package' tarDir in the archive
if (!h.path.startsWith(tarDir))
return false;
const p = h.path.replace(/\\/, '/');
// any .. at the beginning, end, or middle = no good
if (/(\/|)^\.\.(\/|$)/.test(p))
// Package root
const absoluteBasePath = target;
const itemAbsolutePath = resolve(target, h.path.slice(tarDir.length));
if (!itemAbsolutePath.startsWith(absoluteBasePath)) {
return false;
// packages should always be in a 'package' tarDir in the archive
if (!p.startsWith(tarDir))
return false;
}
return true;

@@ -96,3 +95,3 @@ };

}
const tmp = dirname(target) + '/.' + basename(target) + '.' + tmpSuffix();
const tmp = dirname(target) + sep + '.' + basename(target) + '.' + tmpSuffix();
const og = tmp + '.ORIGINAL';

@@ -127,3 +126,3 @@ await Promise.all([rimraf(tmp), rimraf(og)]);

continue;
if (!checkFs(h, tarDir))
if (!checkFs(h, tarDir, tmp))
continue;

@@ -141,3 +140,3 @@ await write(resolve(tmp, h.path.substring(tarDir.length)), body,

continue;
if (!checkFs(h, tarDir))
if (!checkFs(h, tarDir, tmp))
continue;

@@ -144,0 +143,0 @@ await mkdirp(resolve(tmp, h.path.substring(tarDir.length)));

@@ -1,1 +0,1 @@

{"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, rename, writeFile } from 'node:fs/promises'\nimport { basename, dirname, parse, resolve } from 'node:path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'node:zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n const parsed = parse(h.path)\n if (parsed.root) return false\n const p = h.path.replace(/\\\\/, '/')\n // any .. at the beginning, end, or middle = no good\n if (/(\\/|)^\\.\\.(\\/|$)/.test(p)) return false\n // packages should always be in a 'package' tarDir in the archive\n if (!p.startsWith(tarDir)) return false\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + '/.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n !(h = new Header(buffer, offset, ex, gex)).nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]}
{"version":3,"file":"unpack.js","sourceRoot":"","sources":["../../src/unpack.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, rename, writeFile } from 'node:fs/promises'\nimport { basename, dirname, resolve, sep } from 'node:path'\nimport { rimraf } from 'rimraf'\nimport { Header } from 'tar/header'\nimport type { HeaderData } from 'tar/header'\nimport { Pax } from 'tar/pax'\nimport { unzip as unzipCB } from 'node:zlib'\nimport { findTarDir } from './find-tar-dir.ts'\n\nconst unzip = async (input: Buffer) =>\n new Promise<Buffer>(\n (res, rej) =>\n /* c8 ignore start */\n unzipCB(input, (er, result) => (er ? rej(er) : res(result))),\n /* c8 ignore stop */\n )\n\nconst exists = async (path: string): Promise<boolean> => {\n try {\n await lstat(path)\n return true\n } catch {\n return false\n }\n}\n\nlet id = 1\nconst tmp = randomBytes(6).toString('hex') + '.'\nconst tmpSuffix = () => tmp + String(id++)\n\nconst checkFs = (\n h: Header,\n tarDir: string | undefined,\n target: string,\n): h is Header & { path: string } => {\n /* c8 ignore start - impossible */\n if (!h.path) return false\n if (!tarDir) return false\n /* c8 ignore stop */\n h.path = h.path.replace(/[\\\\/]+/g, '/')\n\n // packages should always be in a 'package' tarDir in the archive\n if (!h.path.startsWith(tarDir)) return false\n\n // Package root\n const absoluteBasePath = target\n const itemAbsolutePath = resolve(\n target,\n h.path.slice(tarDir.length),\n )\n\n if (!itemAbsolutePath.startsWith(absoluteBasePath)) {\n return false\n }\n return true\n}\n\nconst write = async (\n path: string,\n body: Buffer,\n executable = false,\n) => {\n await mkdirp(dirname(path))\n // if the mode is world-executable, then make it executable\n // this is needed for some packages that have a file that is\n // not a declared bin, but still used as a cli executable.\n await writeFile(path, body, {\n mode: executable ? 0o777 : 0o666,\n })\n}\n\nconst made = new Set<string>()\nconst making = new Map<string, Promise<boolean>>()\nconst mkdirp = async (d: string) => {\n if (!made.has(d)) {\n const m =\n making.get(d) ??\n mkdir(d, { recursive: true, mode: 0o777 }).then(() =>\n making.delete(d),\n )\n making.set(d, m)\n await m\n made.add(d)\n }\n}\n\nexport const unpack = async (\n tarData: Buffer,\n target: string,\n): Promise<void> => {\n const isGzip = tarData[0] === 0x1f && tarData[1] === 0x8b\n await unpackUnzipped(\n isGzip ? await unzip(tarData) : tarData,\n target,\n )\n}\n\nconst unpackUnzipped = async (\n buffer: Buffer,\n target: string,\n): Promise<void> => {\n /* c8 ignore start */\n const isGzip = buffer[0] === 0x1f && buffer[1] === 0x8b\n if (isGzip) {\n throw error('still gzipped after unzipping', {\n found: isGzip,\n wanted: false,\n })\n }\n /* c8 ignore stop */\n\n // another real quick gutcheck before we get started\n if (buffer.length % 512 !== 0) {\n throw error('Invalid tarball: length not divisible by 512', {\n found: buffer.length,\n })\n }\n if (buffer.length < 1024) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.length },\n )\n }\n // make sure the last kb is all zeros\n for (let i = buffer.length - 1024; i < buffer.length; i++) {\n if (buffer[i] !== 0) {\n throw error(\n 'Invalid tarball: not terminated by 1024 null bytes',\n { found: buffer.subarray(i, i + 10) },\n )\n }\n }\n\n const tmp =\n dirname(target) + sep + '.' + basename(target) + '.' + tmpSuffix()\n const og = tmp + '.ORIGINAL'\n await Promise.all([rimraf(tmp), rimraf(og)])\n\n let succeeded = false\n try {\n let tarDir: string | undefined = undefined\n let offset = 0\n let h: Header\n let ex: HeaderData | undefined = undefined\n let gex: HeaderData | undefined = undefined\n while (\n offset < buffer.length &&\n !(h = new Header(buffer, offset, ex, gex)).nullBlock\n ) {\n offset += 512\n ex = undefined\n gex = undefined\n const size = h.size ?? 0\n const body = buffer.subarray(offset, offset + size)\n // skip invalid headers\n if (!h.cksumValid) continue\n offset += 512 * Math.ceil(size / 512)\n\n // TODO: tarDir might not be named \"package/\"\n // find the first tarDir in the first entry, and use that.\n switch (h.type) {\n case 'File':\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n /* c8 ignore next */\n if (!tarDir) continue\n if (!checkFs(h, tarDir, tmp)) continue\n await write(\n resolve(tmp, h.path.substring(tarDir.length)),\n body,\n // if it's world-executable, it's an executable\n // otherwise, make it read-only.\n 1 === ((h.mode ?? 0x666) & 1),\n )\n break\n\n case 'Directory':\n /* c8 ignore next 2 */\n if (!tarDir) tarDir = findTarDir(h.path, tarDir)\n if (!tarDir) continue\n if (!checkFs(h, tarDir, tmp)) continue\n await mkdirp(resolve(tmp, h.path.substring(tarDir.length)))\n break\n\n case 'GlobalExtendedHeader':\n gex = Pax.parse(body.toString(), gex, true)\n break\n\n case 'ExtendedHeader':\n case 'OldExtendedHeader':\n ex = Pax.parse(body.toString(), ex, false)\n break\n\n case 'NextFileHasLongPath':\n case 'OldGnuLongPath':\n ex ??= Object.create(null) as HeaderData\n ex.path = body.toString().replace(/\\0.*/, '')\n break\n }\n }\n\n const targetExists = await exists(target)\n if (targetExists) await rename(target, og)\n await rename(tmp, target)\n if (targetExists) await rimraf(og)\n succeeded = true\n } finally {\n // do not handle error or obscure throw site, just do the cleanup\n // if it didn't complete successfully.\n if (!succeeded) {\n /* c8 ignore start */\n if (await exists(og)) {\n await rimraf(target)\n await rename(og, target)\n }\n /* c8 ignore stop */\n await rimraf(tmp)\n }\n }\n}\n"]}
{
"name": "@vltpkg/tar",
"description": "An extremely limited and very fast tar extractor",
"version": "1.0.0-rc.9",
"version": "1.0.0-rc.10",
"repository": {

@@ -26,19 +26,19 @@ "type": "git",

"dependencies": {
"rimraf": "^6.0.1",
"tar": "^7.4.3",
"@vltpkg/types": "1.0.0-rc.9",
"@vltpkg/error-cause": "1.0.0-rc.9"
"rimraf": "^6.1.2",
"tar": "^7.5.2",
"@vltpkg/error-cause": "1.0.0-rc.10",
"@vltpkg/types": "1.0.0-rc.10"
},
"devDependencies": {
"@eslint/js": "^9.34.0",
"@types/node": "^22.17.2",
"@eslint/js": "^9.39.1",
"@types/node": "^22.19.2",
"@types/pacote": "^11.1.8",
"eslint": "^9.34.0",
"pacote": "^21.0.0",
"prettier": "^3.6.2",
"tap": "^21.1.0",
"tshy": "^3.0.2",
"eslint": "^9.39.1",
"pacote": "^21.0.4",
"prettier": "^3.7.4",
"tap": "^21.5.0",
"tshy": "^3.1.0",
"typedoc": "~0.27.9",
"typescript": "5.7.3",
"typescript-eslint": "^8.40.0",
"typescript-eslint": "^8.49.0",
"@vltpkg/benchmark": "0.0.0"

@@ -48,3 +48,3 @@ },

"engines": {
"node": ">=22"
"node": ">=22.9.0"
},

@@ -51,0 +51,0 @@ "tap": {