add backend/src/routes/bankingWebhook.ts
This commit is contained in:
parent
5c9a5e4f08
commit
17abbf2a33
69
backend/src/routes/bankingWebhook.ts
Normal file
69
backend/src/routes/bankingWebhook.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { verifyWebhookSignature } from '../modules/banking/signature';
|
||||
import { PaymentService } from '../modules/banking/paymentService';
|
||||
import { IncomingBankWebhookPayload } from '../modules/banking/types';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const paymentService = new PaymentService(prisma);
|
||||
|
||||
/**
|
||||
* Router NUR für den Banking-Webhook. Trägt seinen eigenen
|
||||
* `express.raw()`-Body-Parser direkt an der Route, damit er unabhängig
|
||||
* davon funktioniert, wie der globale JSON-Parser in app.ts registriert ist
|
||||
* (kein Risiko, dass der Stream doppelt gelesen wird).
|
||||
*/
|
||||
export const bankingWebhookRawRouter = Router();
|
||||
|
||||
const BANKING_WEBHOOK_SECRET = process.env.BANKING_WEBHOOK_SECRET!;
|
||||
const WG_ACCOUNT_IBAN = process.env.WG_ACCOUNT_IBAN!; // Schutz vor Fremdkonto-Events
|
||||
|
||||
bankingWebhookRawRouter.post(
|
||||
'/webhooks/banking/transactions',
|
||||
express.raw({ type: 'application/json' }),
|
||||
async (req: Request, res: Response) => {
|
||||
const rawBody: string = req.body instanceof Buffer ? req.body.toString('utf8') : '';
|
||||
const signature = req.header('X-Signature');
|
||||
|
||||
const isValid = verifyWebhookSignature(rawBody, signature, BANKING_WEBHOOK_SECRET);
|
||||
if (!isValid) {
|
||||
return res.status(401).json({ error: 'invalid_signature' });
|
||||
}
|
||||
|
||||
let payload: IncomingBankWebhookPayload;
|
||||
try {
|
||||
payload = JSON.parse(rawBody);
|
||||
} catch {
|
||||
return res.status(400).json({ error: 'invalid_json' });
|
||||
}
|
||||
|
||||
if (payload.accountIban !== WG_ACCOUNT_IBAN) {
|
||||
// Kein Fehler, aber irrelevantes Konto -> ignorieren (200, damit Provider nicht retriggert)
|
||||
return res.status(200).json({ status: 'ignored_account' });
|
||||
}
|
||||
|
||||
if (payload.amount <= 0) {
|
||||
// Nur Zahlungseingänge relevant, keine Abbuchungen
|
||||
return res.status(200).json({ status: 'ignored_outgoing' });
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await paymentService.processIncomingTransaction(payload);
|
||||
return res.status(200).json(result);
|
||||
} catch (err) {
|
||||
console.error('[bankingWebhook] Verarbeitung fehlgeschlagen:', err);
|
||||
// 500, damit der Provider (bei entsprechender Retry-Policy) erneut zustellt
|
||||
return res.status(500).json({ error: 'processing_failed' });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/** Router für die normalen (JSON-basierten) Banking-/Payment-Endpunkte. */
|
||||
export const paymentsRouter = Router();
|
||||
|
||||
/** Cockpit-Endpoint: liefert die Ampel-Übersicht für alle aktiven Verträge. */
|
||||
paymentsRouter.get('/payments/traffic-lights', async (_req: Request, res: Response) => {
|
||||
const lights = await paymentService.getRentTrafficLights();
|
||||
res.status(200).json(lights);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user