From ad6d9bcdd5f3d2b599969c9c2dd261f84c9b3fbe Mon Sep 17 00:00:00 2001 From: Sander Declerck Date: Wed, 12 Nov 2025 14:03:33 +0100 Subject: [PATCH] Simplify interceptor code and rename variables for clarity. --- .../interceptors/interceptorBuilder.js | 87 +++++++++++++------ .../interceptors/npmInterceptor.js | 12 +-- .../interceptors/pipInterceptor.js | 12 +-- .../interceptors/requestInterceptorBuilder.js | 54 ------------ 4 files changed, 69 insertions(+), 96 deletions(-) delete mode 100644 packages/safe-chain/src/registryProxy/interceptors/requestInterceptorBuilder.js diff --git a/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js b/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js index 73bde02..beed1f9 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js +++ b/packages/safe-chain/src/registryProxy/interceptors/interceptorBuilder.js @@ -1,41 +1,32 @@ /** - * @typedef {import('./requestInterceptorBuilder.js').RequestInterceptorBuilder} RequestInterceptorBuilder - * @typedef {import('./requestInterceptorBuilder.js').RequestInterceptor} RequestInterceptor - * - * @typedef {Object} InterceptorBuilder - * @property {(requestFunc: (requestHandlerBuilder: RequestInterceptorBuilder) => Promise) => void} onRequest - * @property {() => Interceptor} build - * * @typedef {Object} Interceptor - * @property {(targetUrl: string) => Promise} handleRequest + * @property {(targetUrl: string) => Promise} handleRequest * @property {(event: string, listener: (...args: any[]) => void) => Interceptor} on * @property {(event: string, ...args: any[]) => boolean} emit + * + * + * @typedef {Object} RequestInterceptionContext + * @property {string} targetUrl + * @property {(packageName: string | undefined, version: string | undefined) => void} blockMalware + * @property {() => RequestInterceptionHandler} build + * + * + * @typedef {Object} RequestInterceptionHandler + * @property {{statusCode: number, message: string} | undefined} blockResponse */ import { EventEmitter } from "events"; -import { createRequestInterceptorBuilder } from "./requestInterceptorBuilder.js"; /** - * @returns {InterceptorBuilder} + * @param {(requestHandlerBuilder: RequestInterceptionContext) => Promise} requestInterceptionFunc + * @returns {Interceptor} */ -export function createInterceptorBuilder() { - /** - * @type {Array<(requestHandlerBuilder: RequestInterceptorBuilder) => Promise>} - */ - const requestHandlers = []; - - return { - onRequest(requestFunc) { - requestHandlers.push(requestFunc); - }, - build() { - return buildInterceptor(requestHandlers); - }, - }; +export function interceptRequests(requestInterceptionFunc) { + return buildInterceptor([requestInterceptionFunc]); } /** - * @param {Array<(requestHandlerBuilder: RequestInterceptorBuilder) => Promise>} requestHandlers + * @param {Array<(requestHandlerBuilder: RequestInterceptionContext) => Promise>} requestHandlers * @returns {Interceptor} */ function buildInterceptor(requestHandlers) { @@ -43,7 +34,7 @@ function buildInterceptor(requestHandlers) { return { async handleRequest(targetUrl) { - const reqInterceptorBuilder = createRequestInterceptorBuilder( + const reqInterceptorBuilder = createRequestContext( targetUrl, eventEmitter ); @@ -63,3 +54,47 @@ function buildInterceptor(requestHandlers) { }, }; } + +/** + * @param {string} targetUrl + * @param {import('events').EventEmitter} eventEmitter + * @returns {RequestInterceptionContext} + */ +function createRequestContext(targetUrl, eventEmitter) { + /** @type {{statusCode: number, message: string} | undefined} */ + let blockResponse = undefined; + + /** + * @param {number} statusCode + * @param {string} message + */ + function blockRequest(statusCode, message) { + blockResponse = { statusCode, message }; + } + + /** + * @param {string | undefined} packageName + * @param {string | undefined} version + */ + function blockMalware(packageName, version) { + blockRequest(403, "Forbidden - blocked by safe-chain"); + + // Emit the malwareBlocked event + eventEmitter.emit("malwareBlocked", { + packageName, + version, + targetUrl, + timestamp: Date.now(), + }); + } + + return { + targetUrl, + blockMalware, + build() { + return { + blockResponse, + }; + }, + }; +} diff --git a/packages/safe-chain/src/registryProxy/interceptors/npmInterceptor.js b/packages/safe-chain/src/registryProxy/interceptors/npmInterceptor.js index 6e33dd0..9a80890 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/npmInterceptor.js +++ b/packages/safe-chain/src/registryProxy/interceptors/npmInterceptor.js @@ -1,5 +1,5 @@ import { isMalwarePackage } from "../../scanning/audit/index.js"; -import { createInterceptorBuilder } from "./interceptorBuilder.js"; +import { interceptRequests } from "./interceptorBuilder.js"; const knownJsRegistries = ["registry.npmjs.org", "registry.yarnpkg.com"]; @@ -22,19 +22,15 @@ export function npmInterceptorForUrl(url) { * @returns {import("./interceptorBuilder.js").Interceptor | undefined} */ function buildNpmInterceptor(registry) { - const builder = createInterceptorBuilder(); - - builder.onRequest(async (req) => { + return interceptRequests(async (reqContext) => { const { packageName, version } = parseNpmPackageUrl( - req.targetUrl, + reqContext.targetUrl, registry ); if (await isMalwarePackage(packageName, version)) { - req.blockMalware(packageName, version, req.targetUrl); + reqContext.blockMalware(packageName, version); } }); - - return builder.build(); } /** diff --git a/packages/safe-chain/src/registryProxy/interceptors/pipInterceptor.js b/packages/safe-chain/src/registryProxy/interceptors/pipInterceptor.js index 7d793d3..212c830 100644 --- a/packages/safe-chain/src/registryProxy/interceptors/pipInterceptor.js +++ b/packages/safe-chain/src/registryProxy/interceptors/pipInterceptor.js @@ -1,5 +1,5 @@ import { isMalwarePackage } from "../../scanning/audit/index.js"; -import { createInterceptorBuilder } from "./interceptorBuilder.js"; +import { interceptRequests } from "./interceptorBuilder.js"; const knownPipRegistries = [ "files.pythonhosted.org", @@ -27,19 +27,15 @@ export function pipInterceptorForUrl(url) { * @returns {import("./interceptorBuilder.js").Interceptor | undefined} */ function buildPipInterceptor(registry) { - const builder = createInterceptorBuilder(); - - builder.onRequest(async (req) => { + return interceptRequests(async (reqContext) => { const { packageName, version } = parsePipPackageFromUrl( - req.targetUrl, + reqContext.targetUrl, registry ); if (await isMalwarePackage(packageName, version)) { - req.blockMalware(packageName, version, req.targetUrl); + reqContext.blockMalware(packageName, version); } }); - - return builder.build(); } /** diff --git a/packages/safe-chain/src/registryProxy/interceptors/requestInterceptorBuilder.js b/packages/safe-chain/src/registryProxy/interceptors/requestInterceptorBuilder.js deleted file mode 100644 index ad1f145..0000000 --- a/packages/safe-chain/src/registryProxy/interceptors/requestInterceptorBuilder.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @typedef {Object} RequestInterceptorBuilder - * @property {string} targetUrl - * @property {(packageName: string | undefined, version: string | undefined, url: string) => void} blockMalware - * @property {() => RequestInterceptor} build - * - * @typedef {Object} RequestInterceptor - * @property {{statusCode: number, message: string} | undefined} blockResponse - */ - -/** - * @param {string} targetUrl - * @param {import('events').EventEmitter} eventEmitter - * @returns {RequestInterceptorBuilder} - */ -export function createRequestInterceptorBuilder(targetUrl, eventEmitter) { - /** @type {{statusCode: number, message: string} | undefined} */ - let blockResponse = undefined; - - /** - * @param {number} statusCode - * @param {string} message - */ - function blockRequest(statusCode, message) { - blockResponse = { statusCode, message }; - } - - /** - * @param {string | undefined} packageName - * @param {string | undefined} version - * @param {string} url - */ - function blockMalware(packageName, version, url) { - blockRequest(403, "Forbidden - blocked by safe-chain"); - - // Emit the malwareBlocked event - eventEmitter.emit("malwareBlocked", { - packageName, - version, - url, - timestamp: Date.now(), - }); - } - - return { - targetUrl, - blockMalware, - build() { - return { - blockResponse, - }; - }, - }; -}