import { createHmac, timingSafeEqual } from "crypto"; export function create_auth_middleware(users) { return function hmac_auth(req, res, next) { const username = req.headers["x-conduit-user"]; const timestamp = req.headers["x-conduit-timestamp"]; const signature = req.headers["x-conduit-signature"]; if (!username || !timestamp || !signature) { return res.status(401).json({ error: "Missing auth headers" }); } const ts = parseInt(timestamp, 10); if (!Number.isFinite(ts) || Date.now() - ts > 30_000) { return res.status(401).json({ error: "Request expired" }); } const user = users[username]; if (!user) { return res.status(401).json({ error: "Unknown user" }); } const raw_body = req.raw_body ?? ""; const expected = createHmac("sha256", user.secret) .update(timestamp + "." + raw_body) .digest("hex"); const sig_buf = Buffer.from(signature, "hex"); const expected_buf = Buffer.from(expected, "hex"); if (sig_buf.length !== expected_buf.length || !timingSafeEqual(sig_buf, expected_buf)) { return res.status(401).json({ error: "Invalid signature" }); } req.conduit_user = username; next(); }; } export function check_can_approve(users, requester_name, submitter_name) { const requester = users[requester_name]; if (!requester) { return false; } return requester.canApprove.includes(submitter_name); }