secure-express-setup
Version:
Military-grade one-command security setup for Express.js applications
61 lines (53 loc) • 2.15 kB
JavaScript
const rateLimit = require("express-rate-limit");
/**
* Setup rate limiting middleware
* @param {Object} options - Rate limit options
* @param {String} redisUrl - Optional Redis URL for distributed rate limiting
*/
function setupRateLimit(options = {}, redisUrl) {
const config = {
windowMs: options.windowMs || 15 * 60 * 1000, // 15 minutes
max: options.max || 100, // limit each IP to 100 requests per windowMs
message: options.message || "Too many requests from this IP, please try again later.",
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
skipFailedRequests: options.skipFailedRequests || false,
skipSuccessfulRequests: options.skipSuccessfulRequests || false,
skip: (req, res) => {
// Skip rate limiting for certain paths (like health checks)
if (req.path === "/health" || req.path === "/api-docs") {
return true;
}
// Skip if rate limit bypass is set (for testing)
if (req.rateLimitBypass) {
return true;
}
return false;
}
};
// If Redis URL is provided, try to use Redis store
if (redisUrl && redisUrl !== "redis://localhost:6379") {
try {
// Try the new way first (rate-limit-redis v4+)
const { RedisStore } = require("rate-limit-redis");
const { createClient } = require("redis");
const redisClient = createClient({
url: redisUrl
});
redisClient.on("error", (err) => {
console.warn("Redis connection error (rate limiting):", err.message);
});
config.store = new RedisStore({
sendCommand: (...args) => redisClient.sendCommand(args),
prefix: "rate-limit:"
});
} catch (err) {
console.warn("Redis store unavailable for rate limiting:", err.message);
console.warn("Falling back to in-memory store");
// Continue with in-memory store
}
}
// Return the rate limit middleware
return rateLimit(config);
}
module.exports = setupRateLimit;