feat(backend): implement comprehensive security and validation
Implement enterprise-grade security measures and input validation: Security Features: - Add Helmet.js for security headers (XSS, clickjacking, MIME protection) - Implement rate limiting (5/15min for auth, 100/15min for API) - Add Socket.IO JWT authentication middleware - Fix JWT auth middleware (remove throw in catch, extend token to 7 days) - Implement centralized error handling with AppError class - Add CORS restrictive configuration Input Validation: - Add express-validator to all routes (auth, streets, tasks, posts, events, rewards, reports, users) - Create comprehensive validation schemas in middleware/validators/ - Consistent error response format for validation failures Additional Features: - Add pagination middleware for all list endpoints - Add Multer file upload middleware (5MB limit, image validation) - Update .env.example with all required environment variables Dependencies Added: - helmet@8.1.0 - express-rate-limit@8.2.1 - express-validator@7.3.0 - multer@1.4.5-lts.1 - cloudinary@2.8.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,15 +4,60 @@ const mongoose = require("mongoose");
|
||||
const cors = require("cors");
|
||||
const http = require("http");
|
||||
const socketio = require("socket.io");
|
||||
const helmet = require("helmet");
|
||||
const rateLimit = require("express-rate-limit");
|
||||
const { errorHandler } = require("./middleware/errorHandler");
|
||||
const socketAuth = require("./middleware/socketAuth");
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const io = socketio(server);
|
||||
const io = socketio(server, {
|
||||
cors: {
|
||||
origin: process.env.FRONTEND_URL || "http://localhost:3000",
|
||||
methods: ["GET", "POST"],
|
||||
credentials: true,
|
||||
},
|
||||
});
|
||||
const port = process.env.PORT || 5000;
|
||||
|
||||
app.use(cors());
|
||||
// Security Headers - Helmet
|
||||
app.use(helmet());
|
||||
|
||||
// CORS Configuration
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.FRONTEND_URL || "http://localhost:3000",
|
||||
credentials: true,
|
||||
}),
|
||||
);
|
||||
|
||||
// Body Parser
|
||||
app.use(express.json());
|
||||
|
||||
// Rate Limiting for Auth Routes (5 requests per 15 minutes)
|
||||
const authLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 5, // 5 requests per windowMs
|
||||
message: {
|
||||
success: false,
|
||||
error: "Too many authentication attempts, please try again later",
|
||||
},
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// General API Rate Limiting (100 requests per 15 minutes)
|
||||
const apiLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||
max: 100, // 100 requests per windowMs
|
||||
message: {
|
||||
success: false,
|
||||
error: "Too many requests, please try again later",
|
||||
},
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// MongoDB Connection
|
||||
mongoose
|
||||
.connect(process.env.MONGO_URI, {
|
||||
@@ -22,39 +67,64 @@ mongoose
|
||||
.then(() => console.log("MongoDB connected"))
|
||||
.catch((err) => console.log("MongoDB connection error:", err));
|
||||
|
||||
// Socket.IO Setup
|
||||
// Socket.IO Authentication Middleware
|
||||
io.use(socketAuth);
|
||||
|
||||
// Socket.IO Setup with Authentication
|
||||
io.on("connection", (socket) => {
|
||||
console.log("New client connected");
|
||||
console.log(`Client connected: ${socket.user.id}`);
|
||||
|
||||
socket.on("joinEvent", (eventId) => {
|
||||
socket.join(eventId);
|
||||
socket.join(`event_${eventId}`);
|
||||
console.log(`User ${socket.user.id} joined event ${eventId}`);
|
||||
});
|
||||
|
||||
socket.on("joinPost", (postId) => {
|
||||
socket.join(`post_${postId}`);
|
||||
console.log(`User ${socket.user.id} joined post ${postId}`);
|
||||
});
|
||||
|
||||
socket.on("eventUpdate", (data) => {
|
||||
io.to(data.eventId).emit("update", data.message);
|
||||
io.to(`event_${data.eventId}`).emit("update", data.message);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("Client disconnected");
|
||||
console.log(`Client disconnected: ${socket.user.id}`);
|
||||
});
|
||||
});
|
||||
|
||||
// Make io available to routes
|
||||
app.set("io", io);
|
||||
|
||||
// Routes
|
||||
const authRoutes = require("./routes/auth");
|
||||
const streetRoutes = require("./routes/streets");
|
||||
const taskRoutes = require("./routes/tasks");
|
||||
const postRoutes = require("./routes/posts");
|
||||
const commentsRoutes = require("./routes/comments");
|
||||
const eventRoutes = require("./routes/events");
|
||||
const rewardRoutes = require("./routes/rewards");
|
||||
const reportRoutes = require("./routes/reports");
|
||||
const badgesRoutes = require("./routes/badges");
|
||||
const aiRoutes = require("./routes/ai");
|
||||
const paymentRoutes = require("./routes/payments");
|
||||
const userRoutes = require("./routes/users");
|
||||
|
||||
// Apply rate limiters
|
||||
app.use("/api/auth/register", authLimiter);
|
||||
app.use("/api/auth/login", authLimiter);
|
||||
app.use("/api", apiLimiter);
|
||||
|
||||
// Routes
|
||||
app.use("/api/auth", authRoutes);
|
||||
app.use("/api/streets", streetRoutes);
|
||||
app.use("/api/tasks", taskRoutes);
|
||||
app.use("/api/posts", postRoutes);
|
||||
app.use("/api/posts", commentsRoutes); // Comments are nested under posts
|
||||
app.use("/api/events", eventRoutes);
|
||||
app.use("/api/rewards", rewardRoutes);
|
||||
app.use("/api/reports", reportRoutes);
|
||||
app.use("/api/badges", badgesRoutes);
|
||||
app.use("/api/ai", aiRoutes);
|
||||
app.use("/api/payments", paymentRoutes);
|
||||
app.use("/api/users", userRoutes);
|
||||
@@ -63,6 +133,9 @@ app.get("/", (req, res) => {
|
||||
res.send("Street Adoption App Backend");
|
||||
});
|
||||
|
||||
// Error Handler Middleware (must be last)
|
||||
app.use(errorHandler);
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`Server running on port ${port}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user