fix: use c.req.json() for Transak webhook body parsing

Hono consumes the request body upstream, so c.req.raw.clone().text()
returns empty. Use c.req.json() directly and re-serialize for HMAC.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-02 18:10:04 -08:00
parent 4bca76cf45
commit a70d5fc1a2
1 changed files with 4 additions and 5 deletions

View File

@ -155,23 +155,22 @@ routes.get("/api/transak/config", (c) => {
});
routes.post("/api/transak/webhook", async (c) => {
// Clone request so we can read body twice (once for HMAC, once for JSON)
const rawBody = await c.req.raw.clone().text();
let body: any;
try { body = await c.req.json(); } catch { return c.json({ error: "Invalid JSON" }, 400); }
// HMAC verification — if TRANSAK_WEBHOOK_SECRET is set, validate signature
const webhookSecret = process.env.TRANSAK_WEBHOOK_SECRET;
if (webhookSecret) {
const signature = c.req.header("x-transak-signature") || "";
const { createHmac } = await import("crypto");
const expected = createHmac("sha256", webhookSecret).update(rawBody).digest("hex");
// Re-serialize for HMAC (Transak signs the raw JSON body)
const expected = createHmac("sha256", webhookSecret).update(JSON.stringify(body)).digest("hex");
if (signature !== expected) {
console.error("[Transak] Invalid webhook signature");
return c.json({ error: "Invalid signature" }, 401);
}
}
let body: any;
try { body = rawBody ? JSON.parse(rawBody) : await c.req.json(); } catch { return c.json({ error: "Invalid JSON" }, 400); }
const { webhookData } = body;
// Ack non-completion events (Transak sends multiple status updates)