import { createHmac } from "node:crypto";
import { isIP } from "node:net";
// The parts of webhooks that need no database (see lib/webhooks.ts), so they can be tested.
/** Loopback, private, link-local, carrier-grade NAT, unspecified and multicast addresses. */
export function isPrivateAddress(ip: string) {
if (isIP(ip) === 4) {
const [a, b] = ip.split(".").map(Number);
return (
a === 0 || a === 10 || a === 127 || a >= 224 || (a === 100 && b >= 64 && b <= 127) || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168)
);
}
const v6 = ip.toLowerCase();
if (v6 === "::" || v6 === "::1") return true;
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(v6);
if (mapped) return isPrivateAddress(mapped[1]);
return /^(fc|fd|fe[89ab]|ff)/.test(v6);
}
/** What a delivery is signed with: sha256= and the HMAC of the body under the hook's secret, as GitHub does. */
export const signature = (secret: string, body: string) => `sha256=${createHmac("sha256", secret).update(body).digest("hex")}`;