diff --git a/backend/src/middleware/validation.js b/backend/src/middleware/validation.js index 4cd7232..42ec460 100644 --- a/backend/src/middleware/validation.js +++ b/backend/src/middleware/validation.js @@ -399,12 +399,12 @@ function validateRequest(req, res, next) { message: e.msg, })); - const isContributionsPath = Boolean( - (req.originalUrl && req.originalUrl.includes('/contributions')) || - (req.baseUrl && req.baseUrl.includes('/contributions')) || - (req.path && req.path.includes('/contributions')) + const usesUnprocessableEntity = Boolean( + (req.originalUrl && (req.originalUrl.includes('/contributions') || req.originalUrl.includes('/withdrawals'))) || + (req.baseUrl && (req.baseUrl.includes('/contributions') || req.baseUrl.includes('/withdrawals'))) || + (req.path && (req.path.includes('/contributions') || req.path.includes('/withdrawals'))) ); - const statusCode = isContributionsPath ? 422 : 400; + const statusCode = usesUnprocessableEntity ? 422 : 400; return res.status(statusCode).json({ error: { diff --git a/backend/src/routes/withdrawals.test.js b/backend/src/routes/withdrawals.test.js index f36c5df..b55b6d9 100644 --- a/backend/src/routes/withdrawals.test.js +++ b/backend/src/routes/withdrawals.test.js @@ -140,6 +140,26 @@ test('POST /api/withdrawals/request creates pending request and logs event', asy assert.ok(calls.some((c) => c.includes('INSERT INTO stellar_transactions'))); }); +test('POST /api/withdrawals/request rejects an invalid Stellar public key with 422', async () => { + const { app, cleanup } = buildApp({ + queryImpl: async (text) => { + if (text.includes('FROM campaigns WHERE id')) { + return { rows: [campaignRow()] }; + } + return { rows: [] }; + }, + }); + + const response = await request(app) + .post('/api/withdrawals/request') + .set('Authorization', 'Bearer token') + .send({ campaign_id: '11111111-1111-1111-1111-111111111111', destination_key: 'not-a-valid-key', amount: '10.0000000' }); + + cleanup(); + assert.equal(response.status, 422); + assert.match(response.body.error.message, /destination_key must be a valid Stellar public key/); +}); + test('POST /api/withdrawals/request returns 400 for failed campaigns', async () => { const { app, cleanup } = buildApp({ role: 'admin',