Some cleanup

This commit is contained in:
Reinier Criel 2026-03-27 14:25:58 -07:00
parent 2df8ce463c
commit 8a4f759a78
2 changed files with 67 additions and 28 deletions

View file

@ -1,4 +1,4 @@
import { getMinimumPackageAgeHours, getNpmMinimumPackageAgeExclusions } from "../../../config/settings.js"; import { getMinimumPackageAgeHours } from "../../../config/settings.js";
import { ui } from "../../../environment/userInteraction.js"; import { ui } from "../../../environment/userInteraction.js";
import { getHeaderValueAsString } from "../../http-utils.js"; import { getHeaderValueAsString } from "../../http-utils.js";
@ -65,16 +65,6 @@ export function modifyNpmInfoResponse(body, headers) {
return body; return body;
} }
// Check if this package is excluded from minimum age filtering
const packageName = bodyJson.name;
const exclusions = getNpmMinimumPackageAgeExclusions();
if (packageName && exclusions.some((pattern) => matchesExclusionPattern(packageName, pattern))) {
ui.writeVerbose(
`Safe-chain: ${packageName} is excluded from minimum package age filtering (minimumPackageAgeExclusions setting).`
);
return body;
}
const cutOff = new Date( const cutOff = new Date(
new Date().getTime() - getMinimumPackageAgeHours() * 3600 * 1000 new Date().getTime() - getMinimumPackageAgeHours() * 3600 * 1000
); );

View file

@ -46,27 +46,43 @@ function buildNpmInterceptor(registry) {
reqContext.targetUrl, reqContext.targetUrl,
registry registry
); );
const minimumAgeChecksEnabled = !skipMinimumPackageAge();
const packageIsExcludedFromMinimumAgeChecks =
packageName && isExcludedFromMinimumPackageAge(packageName);
if (await isMalwarePackage(packageName, version)) { if (await isMalwarePackage(packageName, version)) {
reqContext.blockMalware(packageName, version); reqContext.blockMalware(packageName, version);
return; return;
} }
if (!skipMinimumPackageAge() && isPackageInfoUrl(reqContext.targetUrl)) { if (minimumAgeChecksEnabled && isPackageInfoUrl(reqContext.targetUrl)) {
reqContext.modifyRequestHeaders(modifyNpmInfoRequestHeaders); reqContext.modifyRequestHeaders(modifyNpmInfoRequestHeaders);
reqContext.modifyBody(modifyNpmInfoResponse); reqContext.modifyBody((body, headers) => {
const metadataPackageName = getPackageNameFromMetadataResponse(
body,
headers
);
if (
metadataPackageName &&
isExcludedFromMinimumPackageAge(metadataPackageName)
) {
return body;
}
return modifyNpmInfoResponse(body, headers);
});
return; return;
} }
// For tarball requests the metadata check above is skipped, so we check the // For tarball requests the metadata check above is skipped, so we check the
// new packages list as a fallback (covers e.g. frozen-lockfile installs). // new packages list as a fallback (covers e.g. frozen-lockfile installs).
if (!skipMinimumPackageAge() && packageName && version) { if (
const exclusions = getNpmMinimumPackageAgeExclusions(); minimumAgeChecksEnabled &&
const isExcluded = exclusions.some((pattern) => packageName &&
matchesExclusionPattern(packageName, pattern) version &&
); !packageIsExcludedFromMinimumAgeChecks
) {
if (!isExcluded) {
const newPackagesDatabase = await openNewPackagesDatabase(); const newPackagesDatabase = await openNewPackagesDatabase();
if (newPackagesDatabase.isNewlyReleasedPackage(packageName, version)) { if (newPackagesDatabase.isNewlyReleasedPackage(packageName, version)) {
@ -77,6 +93,39 @@ function buildNpmInterceptor(registry) {
); );
} }
} }
}
}); });
} }
/**
* @param {string} packageName
* @returns {boolean}
*/
function isExcludedFromMinimumPackageAge(packageName) {
const exclusions = getNpmMinimumPackageAgeExclusions();
return exclusions.some((pattern) =>
matchesExclusionPattern(packageName, pattern)
);
}
/**
* @param {Buffer} body
* @param {NodeJS.Dict<string | string[]> | undefined} headers
* @returns {string | undefined}
*/
function getPackageNameFromMetadataResponse(body, headers) {
try {
const contentType = headers?.["content-type"];
const normalizedContentType = Array.isArray(contentType)
? contentType.join(",")
: contentType;
if (!normalizedContentType?.toLowerCase().includes("application/json")) {
return undefined;
}
const bodyJson = JSON.parse(body.toString("utf8"));
return typeof bodyJson.name === "string" ? bodyJson.name : undefined;
} catch {
return undefined;
}
}