From dc6f37b3ecdb6999180bc7275649754956a38db4 Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Thu, 13 Nov 2025 16:27:42 +0100 Subject: [PATCH] Remove etag from response when modifying headers --- .../registryProxy/interceptors/interceptorBuilder.js | 11 ++++++----- .../registryProxy/interceptors/npm/modifyNpmInfo.js | 8 +++++++- .../src/registryProxy/mitmRequestHandler.js | 7 +++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js b/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js index c8ef3fc..362f31a 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js +++ b/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js @@ -11,7 +11,7 @@ import { EventEmitter } from "events"; * @property {string} targetUrl * @property {(packageName: string | undefined, version: string | undefined) => void} blockMalware * @property {(modificationFunc: (headers: NodeJS.Dict) => void) => void} modifyRequestHeaders - * @property {(modificationFunc: (body: Buffer) => Buffer) => void} modifyBody + * @property {(modificationFunc: (body: Buffer, headers: NodeJS.Dict | undefined) => Buffer) => void} modifyBody * @property {() => RequestInterceptionHandler} build * * @@ -19,7 +19,7 @@ import { EventEmitter } from "events"; * @property {{statusCode: number, message: string} | undefined} blockResponse * @property {(headers: NodeJS.Dict | undefined) => void} modifyRequestHeaders * @property {() => boolean} modifiesResponse - * @property {(body: Buffer) => Buffer} modifyBody + * @property {(body: Buffer, headers: NodeJS.Dict | undefined) => Buffer} modifyBody */ /** @@ -67,7 +67,7 @@ function createRequestContext(targetUrl, eventEmitter) { let blockResponse = undefined; /** @type {Array<(headers: NodeJS.Dict) => void>} */ let reqheaderModificationFuncs = []; - /** @type {Array<(body: Buffer) => Buffer>} */ + /** @type {Array<(body: Buffer, headers: NodeJS.Dict | undefined) => Buffer>} */ let modifyBodyFuncs = []; /** @@ -102,13 +102,14 @@ function createRequestContext(targetUrl, eventEmitter) { /** * @param {Buffer} body + * @param {NodeJS.Dict | undefined} headers * @returns {Buffer} */ - function modifyBody(body) { + function modifyBody(body, headers) { let modifiedBody = body; for (var func of modifyBodyFuncs) { - modifiedBody = func(body); + modifiedBody = func(body, headers); } return modifiedBody; diff --git a/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js b/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js index d334c27..54269a8 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js +++ b/packages/safe-chain/src/registryProxy/interceptors/npm/modifyNpmInfo.js @@ -34,9 +34,10 @@ export function isPackageInfoUrl(url) { /** * * @param {Buffer} body + * @param {NodeJS.Dict | undefined} headers * @returns Buffer */ -export function modifyNpmInfoResponse(body) { +export function modifyNpmInfoResponse(body, headers) { try { if (body.byteLength === 0) { return body; @@ -70,6 +71,11 @@ export function modifyNpmInfoResponse(body) { 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. + delete headers["etag"]; + } continue; } } diff --git a/packages/safe-chain/src/registryProxy/mitmRequestHandler.js b/packages/safe-chain/src/registryProxy/mitmRequestHandler.js index 70e0a51..edc114d 100644 --- a/packages/safe-chain/src/registryProxy/mitmRequestHandler.js +++ b/packages/safe-chain/src/registryProxy/mitmRequestHandler.js @@ -188,7 +188,8 @@ function createProxyRequest(hostname, req, res, requestHandler) { res.end("Internal Server Error"); return; } - res.writeHead(proxyRes.statusCode, proxyRes.headers); + + const { statusCode, headers } = proxyRes; if (requestHandler.modifiesResponse()) { /** @type {Array} */ @@ -204,17 +205,19 @@ function createProxyRequest(hostname, req, res, requestHandler) { buffer = gunzipSync(buffer); } - buffer = requestHandler.modifyBody(buffer); + buffer = requestHandler.modifyBody(buffer, headers); if (proxyRes.headers["content-encoding"] === "gzip") { buffer = gzipSync(buffer); } + res.writeHead(statusCode, headers); res.end(buffer); }); } else { // If the response is not being modified, we can // just pipe without the need for buffering the output + res.writeHead(statusCode, headers); proxyRes.pipe(res); } });