/** * Verify an inbound webhook signature. * * Customer use: * * import { verifyWebhookSignature } from "@a4anthony/proctorkit-sdk"; * * app.post("/webhooks/proctor", express.raw(...), async (req, res) => { * const ok = await verifyWebhookSignature({ * body: req.body.toString("utf8"), * header: req.header("X-Proctoring-Signature") ?? "", * secret: process.env.PROCTOR_WEBHOOK_SECRET, * }); * if (!ok) return res.status(401).end(); * // ...handle the event * }); * * The header format is `t=,v1=`. The signed * string is `${t}.${body}` — the same scheme the server uses, the * same Stripe uses. The timestamp protects against replay attacks * (default tolerance 300s). * * Uses Web Crypto so it runs in Node (>=15), browsers, edge runtimes * (Cloudflare Workers, Vercel Edge, Deno), and any V8 isolate that * exposes `crypto.subtle`. No `node:crypto` import — the SDK ships * to browsers and we want one helper for both server and edge. * * Constant-time-equivalent comparison via the byte-by-byte XOR * accumulator below. Web Crypto exposes no `timingSafeEqual` so we * inline the equivalent. */ export interface VerifyWebhookOptions { /** Raw request body as a string (do NOT JSON.parse first). */ body: string; /** The `X-Proctoring-Signature` header value. */ header: string; /** The signing secret you copied from the dashboard. */ secret: string; /** * Reject the signature if the timestamp is older than this many * seconds. Defaults to 300 (5 minutes) — matches Stripe. */ toleranceSeconds?: number; } export declare function verifyWebhookSignature(opts: VerifyWebhookOptions): Promise; //# sourceMappingURL=verify-signature.d.ts.map