141 lines
3.7 KiB
JavaScript
141 lines
3.7 KiB
JavaScript
// 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 logger = require("./utils/logger");
|
|
const morgan = require("morgan");
|
|
|
|
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 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");
|
|
const errorLogger = require("./middleware/errorLogger");
|
|
const apiLogger = require("./middleware/apiLogger");
|
|
|
|
// 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);
|
|
|
|
// HTTP request logging
|
|
app.use(morgan('combined', { stream: logger.stream }));
|
|
|
|
// API request/response logging
|
|
app.use("/api/", apiLogger);
|
|
|
|
// 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")));
|
|
|
|
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(errorLogger);
|
|
app.use(sanitizeError);
|
|
|
|
const PORT = process.env.PORT || 5000;
|
|
|
|
sequelize
|
|
.sync({ alter: true })
|
|
.then(() => {
|
|
logger.info("Database synced successfully");
|
|
|
|
// Start the payout processor
|
|
const payoutJobs = PayoutProcessor.startScheduledPayouts();
|
|
logger.info("Payout processor started");
|
|
|
|
app.listen(PORT, () => {
|
|
logger.info(`Server is running on port ${PORT}`, { port: PORT, environment: env });
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
logger.error("Unable to sync database", { error: err.message, stack: err.stack });
|
|
});
|