const http = require('http'); const targetPorts = [4534, 4474, 4454, 4494]; targetPorts.forEach((targetPort) => { const proxyPort = parseInt(`${targetPort}5`); const server = http.createServer(async (req, res) => { // Construct the full URL using the host header const host = req.headers.host || 'localhost'; const url = new URL(req.url, `http://${host}`); const target = `http://localhost:${targetPort}${url.pathname}${url.search}`; console.log(`\n[INCOMING] ${req.method} ${url.pathname}`); // 1. ECLIPSE TO ACE: Intercept headers and rewrite (e.g., 44545 -> 4454) const aceHeaders = new Headers(); for (const [key, value] of Object.entries(req.headers)) { const strValue = String(value); const modifiedValue = strValue.replaceAll(`${targetPort}5`, targetPort.toString()); aceHeaders.set(key, modifiedValue); if (strValue !== modifiedValue) { console.log(` -> [TO ACE] Modified Header '${key}': sent as ${modifiedValue}`); } } // Node.js streams the request body, so we need to buffer it manually if it exists let reqBody; if (req.method !== "GET" && req.method !== "HEAD") { const chunks = []; for await (const chunk of req) { chunks.push(chunk); } reqBody = Buffer.concat(chunks); } const init = { method: req.method, headers: aceHeaders, ...(reqBody && { body: reqBody }) }; try { const response = await fetch(target, init); console.log(`[ACE RESPONDED] Status: ${response.status}`); // Transfer headers to the Node response response.headers.forEach((value, key) => { // Drop content-length as our payload modification will change the size if (key.toLowerCase() !== "content-length") { res.setHeader(key, value); } }); res.statusCode = response.status; res.statusMessage = response.statusText; // 2. ACE TO ECLIPSE: Intercept JSON payload and rewrite (e.g., 4454 -> 44545) const contentType = response.headers.get("content-type") || ""; if (contentType.includes("application/json") || contentType.includes("text/")) { let bodyText = await response.text(); // THE PROOF: Log exactly what ACE sends back BEFORE we touch it console.log(` -> [RAW ACE RESPONSE]: ${bodyText.substring(0, 250)}...`); if (bodyText.includes(targetPort.toString())) { console.log(` -> [INTERCEPT] Found port ${targetPort}. Rewriting to ${targetPort}5...`); bodyText = bodyText.replaceAll(`localhost:${targetPort}`, `localhost:${targetPort}5`); bodyText = bodyText.replaceAll(`127.0.0.1:${targetPort}`, `127.0.0.1:${targetPort}5`); // Log the payload AFTER the rewrite to confirm the change console.log(` -> [MODIFIED PAYLOAD]: ${bodyText.substring(0, 250)}...`); } res.end(bodyText); } else { // If it's an image, binary file, or other non-text format, handle it gracefully const arrayBuffer = await response.arrayBuffer(); res.end(Buffer.from(arrayBuffer)); } } catch (err) { console.error(`[ERROR]`, err); res.writeHead(502); res.end("Proxy Error"); } }); server.listen(proxyPort, () => { console.log(`Listening on ${proxyPort} -> Forwarding to ${targetPort}`); }); }); console.log(`2-Way Proxy Running. Check the terminal for RAW payload logs...`);