/** * Webhook signature verification for FedPulse webhook deliveries. * * FedPulse signs every outgoing webhook POST with HMAC-SHA256. * Use these utilities to verify that incoming requests are genuinely from * FedPulse and have not been tampered with or replayed. * * ## Signing algorithm: * signed_body = `${timestampSeconds}.${rawPayloadJson}` * signature = HMAC-SHA256(rawSecret, signed_body) → hex * * ## Delivery headers (all present on every POST): * X-FedPulse-Signature : `sha256={hex_hmac}` * X-FedPulse-Timestamp : Unix epoch seconds (string) * X-FedPulse-Event : Event type (e.g. "opportunity.new") * X-FedPulse-Delivery-Id : UUIDv4 delivery identifier * * ## Replay protection: * Reject deliveries where |now − timestamp| > maxAgeSeconds (default 300s). */ import type { WebhookPayload, WebhookVerifyOptions } from './types/webhooks.cjs'; import { FedPulseError } from './errors.cjs'; /** Thrown when webhook signature verification fails. */ export declare class WebhookVerificationError extends FedPulseError { constructor(message: string); } export interface VerifyWebhookInput { /** * The raw request body as a string or Buffer. * Must be the **exact** bytes received, before any JSON parsing. */ rawBody: string | Buffer; /** Value of the `X-FedPulse-Signature` header (e.g. `sha256=abc...`). */ signatureHeader: string; /** Value of the `X-FedPulse-Timestamp` header (Unix epoch seconds as string). */ timestampHeader: string; /** The raw webhook secret you received at creation time (64-char hex string). */ secret: string; /** Verification options. */ options?: WebhookVerifyOptions; } /** * Verify a FedPulse webhook delivery and parse the payload. * * This function performs three checks: * 1. **Format check** — headers are present and in the expected format. * 2. **Timestamp check** — delivery is not older than `maxAgeSeconds`. * 3. **Signature check** — HMAC-SHA256 matches using constant-time comparison. * * Throws `WebhookVerificationError` on any failure. * Returns the parsed, verified `WebhookPayload`. * * @param input Headers, raw body, and secret. * @returns Parsed and verified webhook payload. * * @throws {WebhookVerificationError} If the signature is invalid, the timestamp * is out of range, or the headers are malformed. * * @example * ```ts * // Express.js example (use bodyParser.raw() to get the raw buffer): * app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => { * let payload; * try { * payload = FedPulse.verifyWebhook({ * rawBody: req.body, * signatureHeader: req.headers['x-fedpulse-signature'] as string, * timestampHeader: req.headers['x-fedpulse-timestamp'] as string, * secret: process.env.FEDPULSE_WEBHOOK_SECRET!, * }); * } catch (err) { * return res.status(400).send('Invalid signature'); * } * console.log('Event:', payload.event, 'Data:', payload.data); * res.status(200).send('OK'); * }); * ``` */ export declare function verifyWebhook(input: VerifyWebhookInput): WebhookPayload; /** * Extract the FedPulse webhook headers from a plain headers object. * * Normalises both lowercase and original-casing variants so you don't * have to worry about header casing differences between frameworks. * * @param headers A plain object or Map of request headers. * @returns Extracted signature and timestamp values. * * @example * ```ts * // Works with Express, Fastify, Koa, Next.js API routes, etc. * const { signatureHeader, timestampHeader } = extractWebhookHeaders(req.headers); * const payload = FedPulse.verifyWebhook({ rawBody, signatureHeader, timestampHeader, secret }); * ``` */ export declare function extractWebhookHeaders(headers: Record | Headers): { signatureHeader: string; timestampHeader: string; event: string; deliveryId: string; }; //# sourceMappingURL=webhooks-verify.d.ts.map