const http = require("http"); const fs = require("fs"); const path = require("path"); const PORT = Number(process.env.PORT || 18444); const PYTHON_RISK_URL = process.env.PYTHON_RISK_URL || "http://127.0.0.1:18445"; const DATA_DIR = path.join(__dirname, "data"); const EVENTS_FILE = path.join(DATA_DIR, "events.jsonl"); fs.mkdirSync(DATA_DIR, { recursive: true }); function send(res, status, payload, headers = {}) { const body = typeof payload === "string" ? payload : JSON.stringify(payload, null, 2); res.writeHead(status, { "Content-Type": typeof payload === "string" ? "text/plain; charset=utf-8" : "application/json; charset=utf-8", "X-Demo-Runtime": "node", ...headers }); res.end(body); } function readBody(req, maxBytes = 1024 * 1024) { return new Promise((resolve, reject) => { let raw = ""; let size = 0; req.on("data", chunk => { size += chunk.length; if (size > maxBytes) { reject(new Error("request_body_too_large")); req.destroy(); return; } raw += chunk; }); req.on("end", () => resolve(raw)); req.on("error", reject); }); } function logEvent(event) { fs.appendFileSync(EVENTS_FILE, JSON.stringify({ ...event, at: new Date().toISOString() }) + "\n"); } function parseJson(raw) { if (!raw) return {}; try { return JSON.parse(raw); } catch { return {}; } } async function askRiskEngine(payload) { const response = await fetch(`${PYTHON_RISK_URL}/risk/score`, { method: "POST", headers: { "Content-Type": "application/json", "X-From-Runtime": "node" }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`risk-engine ${response.status}`); return await response.json(); } const products = [ { id: 1, name: "Starter API", price: 79 }, { id: 2, name: "Runtime Mesh", price: 250 }, { id: 3, name: "Enterprise Control", price: 2500 } ]; const users = [ { id: 1, name: "Johnny", role: "skeptical-tester" }, { id: 2, name: "Ops Lead", role: "operator" } ]; const server = http.createServer(async (req, res) => { const url = new URL(req.url, `http://${req.headers.host || "localhost"}`); const ip = req.socket.remoteAddress || "unknown"; logEvent({ runtime: "node", method: req.method, path: url.pathname, ip, johnny_target: req.headers["x-infraveil-johnny-target"] || "" }); try { if ((url.pathname === "/" || url.pathname === "/health") && req.method === "GET") { return send(res, 200, { service: "starter-api", status: "online", runtime: "node", gateway: "infraveil", runtimes: ["node", "python"], message: "Demo API is online. Node serves traffic, Python scores risk, and Infraveil supervises both runtimes." }); } if (url.pathname === "/api/status" && req.method === "GET") { const risk = await askRiskEngine({ path: url.pathname, method: req.method, ip, headers: req.headers }); return send(res, 200, { status: "online", runtime: "node", service: "starter-api", gateway: "infraveil", risk_engine: risk.runtime, risk_score: risk.score, persistent_log: "data/events.jsonl", johnny_target: req.headers["x-infraveil-johnny-target"] || url.searchParams.get("johnny_target") || null }); } if (url.pathname === "/api/data" && req.method === "GET") { return send(res, 200, { records: [ { id: "evt_1", type: "normal_traffic", status: "captured" }, { id: "evt_2", type: "runtime_probe", status: "captured" } ], served_by: "starter-api" }); } if (url.pathname === "/api/products" && req.method === "GET") { return send(res, 200, { products, served_by: "starter-api" }); } if (url.pathname === "/api/users" && req.method === "GET") { return send(res, 200, { users, served_by: "starter-api" }); } if (url.pathname === "/api/orders" && req.method === "POST") { const raw = await readBody(req); const body = parseJson(raw); const risk = await askRiskEngine({ path: url.pathname, method: req.method, ip, body }); const order = { id: `ord_${Date.now()}`, user_id: body.user_id || null, product_id: body.product_id || null, status: body.product_id ? "accepted" : "review", risk_score: risk.score, decision: risk.decision, scored_by: "python-risk-engine", served_by: "starter-api" }; logEvent({ runtime: "node", event: "order_created", order }); return send(res, risk.decision === "deny" ? 403 : body.product_id ? 201 : 202, order); } if (url.pathname === "/api/auth/login" && req.method === "POST") { const raw = await readBody(req); const body = parseJson(raw); const username = String(body.username || "anonymous"); const commonUser = ["admin", "root", "test"].includes(username.toLowerCase()); const risk = await askRiskEngine({ path: url.pathname, method: req.method, ip, body, headers: req.headers }); const blocked = commonUser || risk.decision === "deny"; return send(res, blocked ? 401 : 200, { authenticated: !blocked, username, decision: risk.decision, risk_score: risk.score, scored_by: "python-risk-engine", message: blocked ? "Demo login rejected. Infraveil should record this as auth-shaped traffic." : "Demo login accepted.", served_by: "starter-api" }); } if (url.pathname === "/api/headers" && req.method === "GET") { return send(res, 200, { headers: { user_agent: req.headers["user-agent"] || "", johnny_target: req.headers["x-infraveil-johnny-target"] || "" }, served_by: "starter-api" }); } if (url.pathname === "/api/slow" && req.method === "GET") { const delay = Math.max(50, Math.min(3000, Number(url.searchParams.get("ms") || 500))); await new Promise(resolve => setTimeout(resolve, delay)); return send(res, 200, { status: "ok", delay_ms: delay, served_by: "starter-api" }); } if (url.pathname === "/api/demo-error" && req.method === "GET") { const err = new Error("Intentional demo failure from /api/demo-error"); err.code = "INFRAVEIL_DEMO_ERROR"; throw err; } return send(res, 404, { error: "not_found", path: url.pathname }); } catch (err) { logEvent({ runtime: "node", level: "error", message: err.message, path: url.pathname }); console.error(`[DEMO_ERROR] ${err.stack || err.message}`); return send(res, 500, { error: "demo_api_error", code: err.code || "DEMO_API_ERROR", message: err.message, path: url.pathname }); } }); server.listen(PORT, "127.0.0.1", () => console.log(`Infraveil demo API listening on ${PORT}`));