Spaces:
Sleeping
Sleeping
| import express, { type Express } from "express"; | |
| import cors from "cors"; | |
| import pinoHttp from "pino-http"; | |
| import { rateLimit } from "express-rate-limit"; | |
| import router from "./routes"; | |
| import { logger } from "./lib/logger"; | |
| const app: Express = express(); | |
| app.use( | |
| pinoHttp({ | |
| logger, | |
| serializers: { | |
| req(req) { | |
| return { | |
| id: req.id, | |
| method: req.method, | |
| url: req.url?.split("?")[0], | |
| }; | |
| }, | |
| res(res) { | |
| return { | |
| statusCode: res.statusCode, | |
| }; | |
| }, | |
| }, | |
| }), | |
| ); | |
| const allowedOrigins = process.env.ALLOWED_ORIGINS | |
| ? process.env.ALLOWED_ORIGINS.split(",") | |
| : ["http://localhost:5173", "http://localhost:3000"]; | |
| app.use(cors({ | |
| origin: (origin, callback) => { | |
| if (!origin || allowedOrigins.includes(origin)) { | |
| callback(null, true); | |
| } else { | |
| callback(new Error("Not allowed by CORS")); | |
| } | |
| }, | |
| credentials: true, | |
| })); | |
| app.use(express.json()); | |
| app.use(express.urlencoded({ extended: true })); | |
| // A) General API limiter for all /api routes: window 15 mins, max 500 requests per IP | |
| const generalApiLimiter = rateLimit({ | |
| windowMs: 15 * 60 * 1000, | |
| max: 500, | |
| message: "طلبات كثيرة جداً، حاول مجدداً بعد قليل", | |
| standardHeaders: true, | |
| legacyHeaders: false, | |
| skip: (req) => process.env.NODE_ENV === "test" || req.headers["x-bypass-rate-limit"] === "true", | |
| }); | |
| // B) Auth limiter strictly on /api/auth/login: window 15 mins, max 10 attempts per IP | |
| const authLimiter = rateLimit({ | |
| windowMs: 15 * 60 * 1000, | |
| max: 10, | |
| message: "محاولات تسجيل دخول كثيرة، انتظر 15 دقيقة", | |
| standardHeaders: true, | |
| legacyHeaders: false, | |
| skip: (req) => process.env.NODE_ENV === "test" || req.headers["x-bypass-rate-limit"] === "true", | |
| }); | |
| // C) Upload limiter for attachments/upload routes: window 1 hour, max 50 uploads per IP | |
| const uploadLimiter = rateLimit({ | |
| windowMs: 60 * 60 * 1000, | |
| max: 50, | |
| message: "تجاوزت حد الرفع المسموح به", | |
| standardHeaders: true, | |
| legacyHeaders: false, | |
| skip: (req) => process.env.NODE_ENV === "test" || req.headers["x-bypass-rate-limit"] === "true", | |
| }); | |
| // Apply Rate Limiters before the router middleware | |
| app.use("/api/auth/login", authLimiter); | |
| app.use("/api/attachments", uploadLimiter); | |
| app.use("/api/upload", uploadLimiter); | |
| app.use("/api/tasks/:id/attachments", uploadLimiter); | |
| app.use("/api", generalApiLimiter); | |
| app.use("/api", router); | |
| export default app; | |