prpm 1.1.13 → 1.1.14
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/dist/index.js +65 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -113,6 +113,16 @@ function setPackageIntegrity(lockfile, packageId, tarballBuffer, format) {
|
|
|
113
113
|
const hash = (0, import_crypto.createHash)("sha256").update(tarballBuffer).digest("hex");
|
|
114
114
|
lockfile.packages[lockfileKey].integrity = `sha256-${hash}`;
|
|
115
115
|
}
|
|
116
|
+
function verifyPackageIntegrity(lockfile, packageId, tarballBuffer, format) {
|
|
117
|
+
const lockfileKey = getLockfileKey(packageId, format);
|
|
118
|
+
const pkg = lockfile.packages[lockfileKey];
|
|
119
|
+
if (!pkg || !pkg.integrity) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const hash = (0, import_crypto.createHash)("sha256").update(tarballBuffer).digest("hex");
|
|
123
|
+
const expectedHash = pkg.integrity.replace("sha256-", "");
|
|
124
|
+
return hash === expectedHash;
|
|
125
|
+
}
|
|
116
126
|
function getLockedVersion(lockfile, packageId, format) {
|
|
117
127
|
var _a;
|
|
118
128
|
if (!lockfile) {
|
|
@@ -13989,6 +13999,26 @@ async function handleInstall(packageSpec, options) {
|
|
|
13989
13999
|
}
|
|
13990
14000
|
console.log(` \u2B07\uFE0F Downloading...`);
|
|
13991
14001
|
const tarball = await client.downloadPackage(tarballUrl);
|
|
14002
|
+
const lockfileKeyForVerification = getLockfileKey(packageId, targetFormat);
|
|
14003
|
+
const existingEntry = lockfile == null ? void 0 : lockfile.packages[lockfileKeyForVerification];
|
|
14004
|
+
if (existingEntry == null ? void 0 : existingEntry.integrity) {
|
|
14005
|
+
console.log(` \u{1F512} Verifying integrity...`);
|
|
14006
|
+
const isValid = verifyPackageIntegrity(lockfile, packageId, tarball, targetFormat);
|
|
14007
|
+
if (!isValid) {
|
|
14008
|
+
throw new CLIError(
|
|
14009
|
+
`\u274C Integrity verification failed for ${packageId}
|
|
14010
|
+
|
|
14011
|
+
The downloaded package does not match the expected hash from prpm.lock.
|
|
14012
|
+
This could indicate:
|
|
14013
|
+
\u2022 A corrupted download
|
|
14014
|
+
\u2022 A modified package on the registry
|
|
14015
|
+
\u2022 A potential security issue
|
|
14016
|
+
|
|
14017
|
+
\u{1F4A1} To force installation anyway, delete the package from prpm.lock and retry.`
|
|
14018
|
+
);
|
|
14019
|
+
}
|
|
14020
|
+
console.log(` \u2713 Integrity verified`);
|
|
14021
|
+
}
|
|
13992
14022
|
console.log(` \u{1F4C2} Extracting...`);
|
|
13993
14023
|
const effectiveFormat = format || pkg.format;
|
|
13994
14024
|
const effectiveSubtype = options.subtype || pkg.subtype;
|
|
@@ -14452,6 +14482,18 @@ ${afterFrontmatter}`;
|
|
|
14452
14482
|
await telemetry.shutdown();
|
|
14453
14483
|
}
|
|
14454
14484
|
}
|
|
14485
|
+
function isPathSafe(targetDir, filePath) {
|
|
14486
|
+
const resolvedPath = import_path11.default.resolve(targetDir, filePath);
|
|
14487
|
+
const resolvedTarget = import_path11.default.resolve(targetDir);
|
|
14488
|
+
return resolvedPath.startsWith(resolvedTarget + import_path11.default.sep) || resolvedPath === resolvedTarget;
|
|
14489
|
+
}
|
|
14490
|
+
function hasUnsafePathPatterns(filePath) {
|
|
14491
|
+
if (filePath.includes("..")) return true;
|
|
14492
|
+
if (filePath.startsWith("/")) return true;
|
|
14493
|
+
if (/^[a-zA-Z]:/.test(filePath)) return true;
|
|
14494
|
+
if (filePath.includes("\0")) return true;
|
|
14495
|
+
return false;
|
|
14496
|
+
}
|
|
14455
14497
|
async function extractTarball(tarball, packageId) {
|
|
14456
14498
|
let decompressed;
|
|
14457
14499
|
try {
|
|
@@ -14486,7 +14528,29 @@ async function extractTarball(tarball, packageId) {
|
|
|
14486
14528
|
try {
|
|
14487
14529
|
const extract2 = tar.extract({
|
|
14488
14530
|
cwd: tmpDir,
|
|
14489
|
-
strict:
|
|
14531
|
+
strict: true,
|
|
14532
|
+
// Enable strict mode to reject malformed archives
|
|
14533
|
+
// Security: filter out dangerous entries before extraction
|
|
14534
|
+
filter: (entryPath, entry) => {
|
|
14535
|
+
const entryType = "type" in entry ? entry.type : null;
|
|
14536
|
+
if (entryType === "SymbolicLink" || entryType === "Link") {
|
|
14537
|
+
console.warn(` \u26A0\uFE0F Blocked symlink in package: ${entryPath}`);
|
|
14538
|
+
return false;
|
|
14539
|
+
}
|
|
14540
|
+
if ("isSymbolicLink" in entry && entry.isSymbolicLink()) {
|
|
14541
|
+
console.warn(` \u26A0\uFE0F Blocked symlink in package: ${entryPath}`);
|
|
14542
|
+
return false;
|
|
14543
|
+
}
|
|
14544
|
+
if (hasUnsafePathPatterns(entryPath)) {
|
|
14545
|
+
console.warn(` \u26A0\uFE0F Blocked unsafe path in package: ${entryPath}`);
|
|
14546
|
+
return false;
|
|
14547
|
+
}
|
|
14548
|
+
if (!isPathSafe(tmpDir, entryPath)) {
|
|
14549
|
+
console.warn(` \u26A0\uFE0F Blocked path traversal attempt: ${entryPath}`);
|
|
14550
|
+
return false;
|
|
14551
|
+
}
|
|
14552
|
+
return true;
|
|
14553
|
+
}
|
|
14490
14554
|
});
|
|
14491
14555
|
await (0, import_promises.pipeline)(import_stream.Readable.from(decompressed), extract2);
|
|
14492
14556
|
const extractedFiles = await collectExtractedFiles(tmpDir, excludedNames, import_promises2.default);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prpm",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.14",
|
|
4
4
|
"description": "Prompt Package Manager CLI - Install and manage prompt-based files",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"license": "MIT",
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@octokit/rest": "^22.0.0",
|
|
48
|
-
"@pr-pm/converters": "^1.1.
|
|
49
|
-
"@pr-pm/registry-client": "^2.1.
|
|
50
|
-
"@pr-pm/types": "^1.1.
|
|
48
|
+
"@pr-pm/converters": "^1.1.14",
|
|
49
|
+
"@pr-pm/registry-client": "^2.1.14",
|
|
50
|
+
"@pr-pm/types": "^1.1.14",
|
|
51
51
|
"ajv": "^8.17.1",
|
|
52
52
|
"ajv-formats": "^3.0.1",
|
|
53
53
|
"commander": "^11.1.0",
|