mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Simplify interceptor code and rename variables for clarity.
This commit is contained in:
parent
2cf23d5109
commit
ad6d9bcdd5
4 changed files with 69 additions and 96 deletions
|
|
@ -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>) => void} onRequest
|
|
||||||
* @property {() => Interceptor} build
|
|
||||||
*
|
|
||||||
* @typedef {Object} Interceptor
|
* @typedef {Object} Interceptor
|
||||||
* @property {(targetUrl: string) => Promise<RequestInterceptor>} handleRequest
|
* @property {(targetUrl: string) => Promise<RequestInterceptionHandler>} handleRequest
|
||||||
* @property {(event: string, listener: (...args: any[]) => void) => Interceptor} on
|
* @property {(event: string, listener: (...args: any[]) => void) => Interceptor} on
|
||||||
* @property {(event: string, ...args: any[]) => boolean} emit
|
* @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 { EventEmitter } from "events";
|
||||||
import { createRequestInterceptorBuilder } from "./requestInterceptorBuilder.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {InterceptorBuilder}
|
* @param {(requestHandlerBuilder: RequestInterceptionContext) => Promise<void>} requestInterceptionFunc
|
||||||
|
* @returns {Interceptor}
|
||||||
*/
|
*/
|
||||||
export function createInterceptorBuilder() {
|
export function interceptRequests(requestInterceptionFunc) {
|
||||||
/**
|
return buildInterceptor([requestInterceptionFunc]);
|
||||||
* @type {Array<(requestHandlerBuilder: RequestInterceptorBuilder) => Promise<void>>}
|
|
||||||
*/
|
|
||||||
const requestHandlers = [];
|
|
||||||
|
|
||||||
return {
|
|
||||||
onRequest(requestFunc) {
|
|
||||||
requestHandlers.push(requestFunc);
|
|
||||||
},
|
|
||||||
build() {
|
|
||||||
return buildInterceptor(requestHandlers);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array<(requestHandlerBuilder: RequestInterceptorBuilder) => Promise<void>>} requestHandlers
|
* @param {Array<(requestHandlerBuilder: RequestInterceptionContext) => Promise<void>>} requestHandlers
|
||||||
* @returns {Interceptor}
|
* @returns {Interceptor}
|
||||||
*/
|
*/
|
||||||
function buildInterceptor(requestHandlers) {
|
function buildInterceptor(requestHandlers) {
|
||||||
|
|
@ -43,7 +34,7 @@ function buildInterceptor(requestHandlers) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
async handleRequest(targetUrl) {
|
async handleRequest(targetUrl) {
|
||||||
const reqInterceptorBuilder = createRequestInterceptorBuilder(
|
const reqInterceptorBuilder = createRequestContext(
|
||||||
targetUrl,
|
targetUrl,
|
||||||
eventEmitter
|
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,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { isMalwarePackage } from "../../scanning/audit/index.js";
|
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"];
|
const knownJsRegistries = ["registry.npmjs.org", "registry.yarnpkg.com"];
|
||||||
|
|
||||||
|
|
@ -22,19 +22,15 @@ export function npmInterceptorForUrl(url) {
|
||||||
* @returns {import("./interceptorBuilder.js").Interceptor | undefined}
|
* @returns {import("./interceptorBuilder.js").Interceptor | undefined}
|
||||||
*/
|
*/
|
||||||
function buildNpmInterceptor(registry) {
|
function buildNpmInterceptor(registry) {
|
||||||
const builder = createInterceptorBuilder();
|
return interceptRequests(async (reqContext) => {
|
||||||
|
|
||||||
builder.onRequest(async (req) => {
|
|
||||||
const { packageName, version } = parseNpmPackageUrl(
|
const { packageName, version } = parseNpmPackageUrl(
|
||||||
req.targetUrl,
|
reqContext.targetUrl,
|
||||||
registry
|
registry
|
||||||
);
|
);
|
||||||
if (await isMalwarePackage(packageName, version)) {
|
if (await isMalwarePackage(packageName, version)) {
|
||||||
req.blockMalware(packageName, version, req.targetUrl);
|
reqContext.blockMalware(packageName, version);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { isMalwarePackage } from "../../scanning/audit/index.js";
|
import { isMalwarePackage } from "../../scanning/audit/index.js";
|
||||||
import { createInterceptorBuilder } from "./interceptorBuilder.js";
|
import { interceptRequests } from "./interceptorBuilder.js";
|
||||||
|
|
||||||
const knownPipRegistries = [
|
const knownPipRegistries = [
|
||||||
"files.pythonhosted.org",
|
"files.pythonhosted.org",
|
||||||
|
|
@ -27,19 +27,15 @@ export function pipInterceptorForUrl(url) {
|
||||||
* @returns {import("./interceptorBuilder.js").Interceptor | undefined}
|
* @returns {import("./interceptorBuilder.js").Interceptor | undefined}
|
||||||
*/
|
*/
|
||||||
function buildPipInterceptor(registry) {
|
function buildPipInterceptor(registry) {
|
||||||
const builder = createInterceptorBuilder();
|
return interceptRequests(async (reqContext) => {
|
||||||
|
|
||||||
builder.onRequest(async (req) => {
|
|
||||||
const { packageName, version } = parsePipPackageFromUrl(
|
const { packageName, version } = parsePipPackageFromUrl(
|
||||||
req.targetUrl,
|
reqContext.targetUrl,
|
||||||
registry
|
registry
|
||||||
);
|
);
|
||||||
if (await isMalwarePackage(packageName, version)) {
|
if (await isMalwarePackage(packageName, version)) {
|
||||||
req.blockMalware(packageName, version, req.targetUrl);
|
reqContext.blockMalware(packageName, version);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue