Vectrum
Sign In
22 lines · 1.0 KB · TypeScript
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")}`;