diff --git a/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js b/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js index 2ad8a68..acb7d07 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js +++ b/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js @@ -7,7 +7,8 @@ let hasSuppressedVersions = false; * @param {NodeJS.Dict} headers */ export function modifyNpmInfoRequestHeaders(headers) { - if (headers["accept"]?.includes("application/vnd.npm.install-v1+json")) { + const accept = getHeaderValueAsString(headers, "accept"); + if (accept?.includes("application/vnd.npm.install-v1+json")) { // The npm registry sometimes serves a more compact format that lacks // the time metadata we need to filter out too new packages. // Force the registry to return the full metadata by changing the Accept header. @@ -41,6 +42,11 @@ export function isPackageInfoUrl(url) { */ export function modifyNpmInfoResponse(body, headers) { try { + const contentType = getHeaderValueAsString(headers, "content-type"); + if (!contentType?.toLowerCase().includes("application/json")) { + return body; + } + if (body.byteLength === 0) { return body; } @@ -74,9 +80,10 @@ export function modifyNpmInfoResponse(body, headers) { if (timestamp > cutOff) { deleteVersionFromJson(bodyJson, version); if (headers) { - // When modifying the response, the etag no longer matches the content - // so the etag needs to be removed before sending the response. + // When modifying the response, the etag and last-modified headers + // no longer match the content so they needs to be removed before sending the response. delete headers["etag"]; + delete headers["last-modified"]; } continue; } @@ -163,3 +170,21 @@ function getMostRecentTag(tagList) { export function getHasSuppressedVersions() { return hasSuppressedVersions; } + +/** + * @param {NodeJS.Dict | undefined} headers + * @param {string} headerName + */ +function getHeaderValueAsString(headers, headerName) { + if (!headers) { + return undefined; + } + + let header = headers[headerName]; + + if (Array.isArray(header)) { + return header.join(", "); + } + + return header; +} diff --git a/packages/safe-chain/src/registryProxy/interceptors/npm/npmInterceptor.minPackageAge.spec.js b/packages/safe-chain/src/registryProxy/interceptors/npm/npmInterceptor.minPackageAge.spec.js index ab3802b..2ff5a52 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/npm/npmInterceptor.minPackageAge.spec.js +++ b/packages/safe-chain/src/registryProxy/interceptors/npm/npmInterceptor.minPackageAge.spec.js @@ -231,23 +231,6 @@ describe("npmInterceptor minimum package age", async () => { assert.equal(modifiedJson["dist-tags"]["alpha"], undefined); }); - /** - * @param {import("../interceptorBuilder.js").Interceptor} interceptor - * @param {string} body - * @returns {Promise} - */ - async function runModifyNpmInfoRequest(url, body) { - const interceptor = npmInterceptorForUrl(url); - const requestHandler = await interceptor.handleRequest(url); - - if (requestHandler.modifiesResponse()) { - const modifiedBuffer = requestHandler.modifyBody(Buffer.from(body)); - return modifiedBuffer.toString("utf8"); - } - - return body; - } - it("Should not filter packages when skipMinimumPackageAge is enabled", async () => { minimumPackageAgeSettings = 5; skipMinimumPackageAgeSetting = true; @@ -296,4 +279,23 @@ describe("npmInterceptor minimum package age", async () => { return date; } + + /** + * @param {import("../interceptorBuilder.js").Interceptor} interceptor + * @param {string} body + * @returns {Promise} + */ + async function runModifyNpmInfoRequest(url, body) { + const interceptor = npmInterceptorForUrl(url); + const requestHandler = await interceptor.handleRequest(url); + + if (requestHandler.modifiesResponse()) { + const modifiedBuffer = requestHandler.modifyBody(Buffer.from(body), { + ["content-type"]: "application/json", + }); + return modifiedBuffer.toString("utf8"); + } + + return body; + } });