mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Merge branch 'main' into verbose-logging
This commit is contained in:
commit
be6a6dccd9
62 changed files with 1243 additions and 41 deletions
|
|
@ -3,6 +3,11 @@ import { generateCertForHost } from "./certUtils.js";
|
|||
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||
import { ui } from "../environment/userInteraction.js";
|
||||
|
||||
/**
|
||||
* @param {import("http").IncomingMessage} req
|
||||
* @param {import("net").Socket} clientSocket
|
||||
* @param {(target: string) => Promise<boolean>} isAllowed
|
||||
*/
|
||||
export function mitmConnect(req, clientSocket, isAllowed) {
|
||||
ui.writeVerbose(`Safe-chain: Set up MITM tunnel for ${req.url}`);
|
||||
const { hostname } = new URL(`http://${req.url}`);
|
||||
|
|
@ -18,6 +23,16 @@ export function mitmConnect(req, clientSocket, isAllowed) {
|
|||
|
||||
const server = createHttpsServer(hostname, isAllowed);
|
||||
|
||||
server.on("error", (err) => {
|
||||
ui.writeError(`Safe-chain: HTTPS server error: ${err.message}`);
|
||||
// @ts-expect-error Property 'headersSent' does not exist on type 'Socket'
|
||||
if (!clientSocket.headersSent) {
|
||||
clientSocket.end("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
||||
} else if (clientSocket.writable) {
|
||||
clientSocket.end();
|
||||
}
|
||||
});
|
||||
|
||||
// Establish the connection
|
||||
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
||||
|
||||
|
|
@ -25,10 +40,22 @@ export function mitmConnect(req, clientSocket, isAllowed) {
|
|||
server.emit("connection", clientSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} hostname
|
||||
* @param {(target: string) => Promise<boolean>} isAllowed
|
||||
* @returns {import("https").Server}
|
||||
*/
|
||||
function createHttpsServer(hostname, isAllowed) {
|
||||
const cert = generateCertForHost(hostname);
|
||||
|
||||
/**
|
||||
* @param {import("http").IncomingMessage} req
|
||||
* @param {import("http").ServerResponse} res
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function handleRequest(req, res) {
|
||||
// @ts-expect-error req.url might be undefined
|
||||
const pathAndQuery = getRequestPathAndQuery(req.url);
|
||||
const targetUrl = `https://${hostname}${pathAndQuery}`;
|
||||
|
||||
|
|
@ -43,15 +70,21 @@ function createHttpsServer(hostname, isAllowed) {
|
|||
forwardRequest(req, hostname, res);
|
||||
}
|
||||
|
||||
return https.createServer(
|
||||
const server = https.createServer(
|
||||
{
|
||||
key: cert.privateKey,
|
||||
cert: cert.certificate,
|
||||
},
|
||||
handleRequest
|
||||
);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRequestPathAndQuery(url) {
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
const parsedUrl = new URL(url);
|
||||
|
|
@ -60,6 +93,11 @@ function getRequestPathAndQuery(url) {
|
|||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("http").IncomingMessage} req
|
||||
* @param {string} hostname
|
||||
* @param {import("http").ServerResponse} res
|
||||
*/
|
||||
function forwardRequest(req, hostname, res) {
|
||||
const proxyReq = createProxyRequest(hostname, req, res);
|
||||
|
||||
|
|
@ -71,6 +109,11 @@ function forwardRequest(req, hostname, res) {
|
|||
res.end("Bad Gateway");
|
||||
});
|
||||
|
||||
req.on("error", (err) => {
|
||||
ui.writeError(`Safe-chain: Error reading client request: ${err.message}`);
|
||||
proxyReq.destroy();
|
||||
});
|
||||
|
||||
req.on("data", (chunk) => {
|
||||
proxyReq.write(chunk);
|
||||
});
|
||||
|
|
@ -83,7 +126,15 @@ function forwardRequest(req, hostname, res) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} hostname
|
||||
* @param {import("http").IncomingMessage} req
|
||||
* @param {import("http").ServerResponse} res
|
||||
*
|
||||
* @returns {import("http").ClientRequest}
|
||||
*/
|
||||
function createProxyRequest(hostname, req, res) {
|
||||
/** @type {import("http").RequestOptions} */
|
||||
const options = {
|
||||
hostname: hostname,
|
||||
port: 443,
|
||||
|
|
@ -92,7 +143,9 @@ function createProxyRequest(hostname, req, res) {
|
|||
headers: { ...req.headers },
|
||||
};
|
||||
|
||||
delete options.headers.host;
|
||||
if (options.headers && "host" in options.headers) {
|
||||
delete options.headers.host;
|
||||
}
|
||||
|
||||
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
||||
if (httpsProxy) {
|
||||
|
|
@ -100,6 +153,17 @@ function createProxyRequest(hostname, req, res) {
|
|||
}
|
||||
|
||||
const proxyReq = https.request(options, (proxyRes) => {
|
||||
proxyRes.on("error", (err) => {
|
||||
ui.writeError(
|
||||
`Safe-chain: Error reading upstream response: ${err.message}`
|
||||
);
|
||||
if (!res.headersSent) {
|
||||
res.writeHead(502);
|
||||
res.end("Bad Gateway");
|
||||
}
|
||||
});
|
||||
|
||||
// @ts-expect-error statusCode might be undefined
|
||||
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
||||
proxyRes.pipe(res);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue