// Load environment-specific config const env = process.env.NODE_ENV || "dev"; const envFile = `.env.${env}`; require("dotenv").config({ path: envFile, }); const express = require("express"); const cors = require("cors"); const bodyParser = require("body-parser"); const path = require("path"); const helmet = require("helmet"); const { sequelize } = require("./models"); // Import from models/index.js to ensure associations are loaded const { cookieParser } = require("./middleware/csrf"); const authRoutes = require("./routes/auth"); const userRoutes = require("./routes/users"); const itemRoutes = require("./routes/items"); const rentalRoutes = require("./routes/rentals"); const messageRoutes = require("./routes/messages"); const betaRoutes = require("./routes/beta"); const itemRequestRoutes = require("./routes/itemRequests"); const stripeRoutes = require("./routes/stripe"); const mapsRoutes = require("./routes/maps"); const PayoutProcessor = require("./jobs/payoutProcessor"); const app = express(); // Import security middleware const { enforceHTTPS, securityHeaders, addRequestId, sanitizeError, } = require("./middleware/security"); const { generalLimiter } = require("./middleware/rateLimiter"); // Apply security middleware app.use(enforceHTTPS); app.use(addRequestId); app.use(securityHeaders); // Security headers with Helmet app.use( helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "https://cdn.jsdelivr.net"], fontSrc: ["'self'"], scriptSrc: ["'self'", "https://accounts.google.com"], imgSrc: ["'self'"], connectSrc: ["'self'"], frameSrc: ["'self'", "https://accounts.google.com"], }, }, }) ); // Cookie parser for CSRF app.use(cookieParser); // General rate limiting for all routes app.use("/api/", generalLimiter); // CORS with security settings app.use( cors({ origin: process.env.FRONTEND_URL || "http://localhost:3000", credentials: true, optionsSuccessStatus: 200, }) ); // Body parsing with size limits app.use( bodyParser.json({ limit: "1mb", verify: (req, res, buf) => { // Store raw body for webhook verification req.rawBody = buf; }, }) ); app.use( bodyParser.urlencoded({ extended: true, limit: "1mb", parameterLimit: 100, // Limit number of parameters }) ); // Serve static files from uploads directory app.use("/uploads", express.static(path.join(__dirname, "uploads"))); // Beta verification route (doesn't require auth) app.use("/api/beta", betaRoutes); app.use("/api/auth", authRoutes); app.use("/api/users", userRoutes); app.use("/api/items", itemRoutes); app.use("/api/rentals", rentalRoutes); app.use("/api/messages", messageRoutes); app.use("/api/item-requests", itemRequestRoutes); app.use("/api/stripe", stripeRoutes); app.use("/api/maps", mapsRoutes); app.get("/", (req, res) => { res.json({ message: "CommunityRentals.App API is running!" }); }); // Error handling middleware (must be last) app.use(sanitizeError); const PORT = process.env.PORT || 5000; sequelize .sync({ alter: true }) .then(() => { console.log("Database synced"); // Start the payout processor const payoutJobs = PayoutProcessor.startScheduledPayouts(); app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); }) .catch((err) => { console.error("Unable to sync database:", err); });