diff --git a/server/routes/api/checkout.js b/server/routes/api/checkout.js index d0b91aaf3..2690ac4a8 100644 --- a/server/routes/api/checkout.js +++ b/server/routes/api/checkout.js @@ -12,6 +12,31 @@ const Letter = require('../../db/models/letter') const router = express.Router() +const Joi = require('joi'); // For input validation + +// Validation schema for incoming data +const sessionSchema = Joi.object({ + donation: Joi.number().positive().max(10000).required() // Limit donation amount to prevent abuse + .messages({ + 'number.base': 'Donation must be a number.', + 'number.positive': 'Donation must be a positive number.', + 'number.max': 'Donation exceeds the allowed limit.', + 'any.required': 'Donation is required.' + }), + user: Joi.object({ + email: Joi.string().email().required() + .messages({ + 'string.email': 'A valid email is required.', + 'any.required': 'User email is required.' + }) + }).required(), + letter: Joi.string().max(300).optional() // Limit the size to prevent long data + .messages({ + 'string.max': 'Letter cannot exceed 300 characters.' + }) +}).unknown(false); // Disallow any additional, unexpected fields + + class CheckoutError extends Error { constructor(message) { super(message) @@ -20,10 +45,40 @@ class CheckoutError extends Error { } router.post('/create-checkout-session', async (req, res) => { - const { donation, user, letter } = req.body - const origin = req.get('origin') + try { + // Validate incoming data against the schema + const { donation, user, letter } = await sessionSchema.validateAsync(req.body); + + // Validate origin to ensure the request is coming from trusted sources + const origin = req.get('origin'); + // Trusted origins to be added as a list below, environment variable, config file, or in the DB + const allowedOrigins = ['https://yourtrusteddomain.com', 'https://anothertrusteddomain.com']; + if (!allowedOrigins.includes(origin)) { + console.warn(`Untrusted origin attempted to create session: ${origin}`); + return res.status(403).json({ error: 'Forbidden request from untrusted origin.' }); + } + + // Log the origin without sensitive information + console.log(`Valid origin: ${origin}`); + + // Continue with checkout session creation logic... + // (You can add the session creation logic here) - console.log(`origin: ${origin}`) + return res.status(200).json({ message: 'Checkout session created successfully' }); + + } catch (error) { + // Error handling + if (error.isJoi) { + // Handle validation errors + console.error('Validation error:', error.details); + return res.status(400).json({ error: 'Invalid input data' }); + } + + // Catch any unexpected errors + console.error('Error creating checkout session:', error); + return res.status(500).json({ error: 'Internal server error' }); + } + try { const presenter = new PaymentPresenter()