AikidoSec-safe-chain/packages/safe-chain/src/registryProxy/mitmRequestHandler.js
2025-10-01 08:10:49 +02:00

84 lines
2 KiB
JavaScript

import https from "https";
import { generateCertForHost } from "./certUtils.js";
export function mitmConnect(req, clientSocket, isAllowed) {
const { hostname } = new URL(`http://${req.url}`);
const server = createHttpsServer(hostname, isAllowed);
// Establish the connection
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
// Hand off the socket to the HTTPS server
server.emit("connection", clientSocket);
}
function createHttpsServer(hostname, isAllowed) {
const cert = generateCertForHost(hostname);
async function handleRequest(req, res) {
const pathAndQuery = getRequestPathAndQuery(req.url);
const targetUrl = `https://${hostname}${pathAndQuery}`;
if (!(await isAllowed(targetUrl))) {
res.writeHead(403, "Forbidden - blocked by safe-chain");
res.end("Blocked by safe-chain");
return;
}
// Collect request body
forwardRequest(req, hostname, res);
}
return https.createServer(
{
key: cert.privateKey,
cert: cert.certificate,
},
handleRequest
);
}
function getRequestPathAndQuery(url) {
if (url.startsWith("http://") || url.startsWith("https://")) {
const parsedUrl = new URL(url);
return parsedUrl.pathname + parsedUrl.search + parsedUrl.hash;
}
return url;
}
function forwardRequest(req, hostname, res) {
const proxyReq = createProxyRequest(hostname, req, res);
proxyReq.on("error", () => {
res.writeHead(502);
res.end("Bad Gateway");
});
req.on("data", (chunk) => {
proxyReq.write(chunk);
});
req.on("end", () => {
proxyReq.end();
});
}
function createProxyRequest(hostname, req, res) {
const options = {
hostname: hostname,
port: 443,
path: req.url,
method: req.method,
headers: { ...req.headers },
};
delete options.headers.host;
const proxyReq = https.request(options, (proxyRes) => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
return proxyReq;
}