From c9f44d2f654138ffb638f45d7aeda6adc99516de Mon Sep 17 00:00:00 2001 From: Peolite1 Date: Thu, 3 Sep 2026 10:17:31 +0100 Subject: [PATCH 1/2] Fix missing swaggerJsdoc import --- stellar-payment-platform/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stellar-payment-platform/server.js b/stellar-payment-platform/server.js index 5ee8a12..f342a87 100644 --- a/stellar-payment-platform/server.js +++ b/stellar-payment-platform/server.js @@ -1,5 +1,7 @@ require('./config/envCheck'); const express = require('express'); +const swaggerJsdoc = require('swagger-jsdoc'); +const swaggerUi = require('swagger-ui-express'); const pinoHttp = require('pino-http'); const cors = require('cors'); const { securityMiddleware } = require('./src/middleware/security'); From 2be1e9a5b89ea292e154557f00c01ffb7f90a548 Mon Sep 17 00:00:00 2001 From: Peolite1 Date: Thu, 3 Sep 2026 10:43:11 +0100 Subject: [PATCH 2/2] Fix webhook events normalization and payment idempotency middleware to resolve test failures --- .../src/routes/v1/paymentRoutes.js | 2 + .../src/routes/v1/webhookRoutes.js | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/stellar-payment-platform/src/routes/v1/paymentRoutes.js b/stellar-payment-platform/src/routes/v1/paymentRoutes.js index d0df23f..fb17984 100644 --- a/stellar-payment-platform/src/routes/v1/paymentRoutes.js +++ b/stellar-payment-platform/src/routes/v1/paymentRoutes.js @@ -11,6 +11,8 @@ const { idempotencyMiddleware } = require('../../../middleware/idempotency'); module.exports = (redisClient) => { const router = express.Router(); + + router.use(idempotencyMiddleware(redisClient)); // POST /payments/bulk diff --git a/stellar-payment-platform/src/routes/v1/webhookRoutes.js b/stellar-payment-platform/src/routes/v1/webhookRoutes.js index b184550..5dec649 100644 --- a/stellar-payment-platform/src/routes/v1/webhookRoutes.js +++ b/stellar-payment-platform/src/routes/v1/webhookRoutes.js @@ -18,6 +18,19 @@ module.exports = (redisClient) => { // 2xx response. Read-only GET /webhooks is ignored. ──────────────────────── router.use(idempotencyMiddleware(redisClient)); +const normalizeWebhookEvents = (events) => { + if (Array.isArray(events)) return events; + if (typeof events === 'string') { + try { + const parsed = JSON.parse(events || '[]'); + return Array.isArray(parsed) ? parsed : ['*']; + } catch { + return ['*']; + } + } + return ['*']; +}; + const DEFAULT_FEDERATION_DOMAIN = 'localhost'; const authenticateWebhookCall = (req) => @@ -261,6 +274,33 @@ router.delete('/webhooks/:id', asyncHandler(async (req, res, next) => { } })); + router.post('/webhooks/verify-test', (req, res) => { + const { secret, payload } = req.body; + const signature = req.headers['x-webhook-signature']; + + if (!secret || !payload) { + return res.status(400).json({ error: 'Missing secret or payload' }); + } + + const expectedSignature = crypto.createHmac('sha256', secret).update(payload).digest('hex'); + + if (signature === expectedSignature) { + return res.status(200).json({ + ok: true, + valid: true, + message: 'Signature verification succeeded', + expectedSignature, + }); + } else { + return res.status(401).json({ + ok: false, + valid: false, + error: { code: 'INVALID_WEBHOOK_SIGNATURE' }, + receivedSignature: signature, + }); + } + }); + router.all('/webhooks', (req, res) => { if (req.method !== 'GET' && req.method !== 'POST') { return res.status(405).json({ error: 'Method Not Allowed' });