diff --git a/hotel-booking-backend/src/index.ts b/hotel-booking-backend/src/index.ts index 4059eb5..c539523 100644 --- a/hotel-booking-backend/src/index.ts +++ b/hotel-booking-backend/src/index.ts @@ -1,4 +1,4 @@ -import express, { Request, Response } from "express"; +import express, { Request, Response, NextFunction } from "express"; import cors from "cors"; import "dotenv/config"; import mongoose from "mongoose"; @@ -87,26 +87,36 @@ app.use(helmet()); // Trust proxy for production (fixes rate limiting issues) app.set("trust proxy", 1); -// Rate limiting - more lenient for payment endpoints +// Rate limiting configurations const generalLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes - max: 200, // Increased limit for general requests + max: 200, message: "Too many requests from this IP, please try again later.", standardHeaders: true, legacyHeaders: false, }); -// Special limiter for payment endpoints const paymentLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes - max: 50, // Higher limit for payment requests + max: 50, message: "Too many payment requests, please try again later.", standardHeaders: true, legacyHeaders: false, }); +const authLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 10, // Limit each IP to 10 register/login requests per window + message: "Too many authentication attempts, please try again after 15 minutes", + standardHeaders: true, + legacyHeaders: false, +}); + +// Apply limiters app.use("/api/", generalLimiter); app.use("/api/hotels/*/bookings/payment-intent", paymentLimiter); +app.use("/api/auth/login", authLimiter); +app.use("/api/auth/register", authLimiter); // Compression middleware app.use(compression()); @@ -121,75 +131,27 @@ const allowedOrigins = [ "https://mern-booking-hotel.netlify.app", "https://mern-booking-hotel.netlify.app/", ].filter((origin): origin is string => Boolean(origin)); + app.use( cors({ origin: (origin, callback) => { - // Allow requests with no origin (like mobile apps or curl requests) if (!origin) return callback(null, true); - - // Allow all Netlify preview URLs - if (origin.includes("netlify.app")) { - return callback(null, true); - } - - if (allowedOrigins.includes(origin)) { - return callback(null, true); - } - - // Log blocked origins in development - if (process.env.NODE_ENV === "development") { - console.log("CORS blocked origin:", origin); - } - + if (origin.includes("netlify.app")) return callback(null, true); + if (allowedOrigins.includes(origin)) return callback(null, true); return callback(new Error("Not allowed by CORS")); }, credentials: true, optionsSuccessStatus: 204, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allowedHeaders: [ - "Content-Type", - "Authorization", - "Cookie", - "X-Requested-With", - ], + allowedHeaders: ["Content-Type", "Authorization", "Cookie", "X-Requested-With"], }) ); -// Explicit preflight handler for all routes -app.options( - "*", - cors({ - origin: (origin, callback) => { - // Allow requests with no origin (like mobile apps or curl requests) - if (!origin) return callback(null, true); - - // Allow all Netlify preview URLs - if (origin.includes("netlify.app")) { - return callback(null, true); - } - - if (allowedOrigins.includes(origin)) { - return callback(null, true); - } - return callback(new Error("Not allowed by CORS")); - }, - credentials: true, - optionsSuccessStatus: 204, - methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allowedHeaders: [ - "Content-Type", - "Authorization", - "Cookie", - "X-Requested-With", - ], - }) -); app.use(cookieParser()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use((req, res, next) => { - // Ensure Vary header for CORS res.header("Vary", "Origin"); next(); }); @@ -198,6 +160,7 @@ app.get("/", (req: Request, res: Response) => { res.send("
+ We encountered an unexpected error. Please try refreshing the page. +
+ +