configurable rate limiting

This commit is contained in:
Dan Janosik 2024-11-07 15:52:15 -05:00
parent e5aa5592a1
commit 5a6f181852
No known key found for this signature in database
GPG key ID: 70C0B166321C0AF8
3 changed files with 45 additions and 27 deletions

View file

@ -224,3 +224,9 @@
# CDN base url; if S3 details are given, this will probably be a CloudFront path for assets that are uploaded at launch
#BTCEXP_CDN_BASE_URL=xxx
# Rate limiting
# Window size, in minutes, set to -1 to disable rate limiting
#BTCEXP_RATE_LIMIT_WINDOW_MINUTES=xx
# Window max requests allowed
#BTCEXP_RATE_LIMIT_WINDOW_MAX_REQUESTS=xxx

61
app.js
View file

@ -240,35 +240,42 @@ expressApp.use(config.baseUrl, express.static(path.join(__dirname, 'public'), {
// https://www.npmjs.com/package/express-rate-limit
const rateLimitWindowMinutes = 15;
const rateLimitWindowMaxRequests = 200;
const rateLimiter = rateLimit({
windowMs: rateLimitWindowMinutes * 60 * 1000, // 15 minutes
limit: rateLimitWindowMaxRequests, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
skip: function (req, res) {
if (req.originalUrl.includes("/snippet/")) {
return true;
const rateLimitWindowMinutes = config.rateLimiting.windowMinutes;
const rateLimitWindowMaxRequests = config.rateLimiting.windowMaxRequests;
if (rateLimitWindowMinutes == -1) {
debugLog("Disabling rate limiting");
} else {
debugLog(`Enabling rate limiting: ${rateLimitWindowMaxRequests} requests per ${rateLimitWindowMinutes}min`);
const rateLimiter = rateLimit({
windowMs: rateLimitWindowMinutes * 60 * 1000, // 15 minutes
limit: rateLimitWindowMaxRequests, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
legacyHeaders: false, // Disable the `X-RateLimit-*` headers.
skip: function (req, res) {
if (req.originalUrl.includes("/snippet/")) {
return true;
}
if (req.originalUrl.includes("/api/")) {
return true;
}
return false;
},
handler: function (req, res, next) {
debugErrorLog(`Rate-limiting request: ip=${req.ip}, req=${req.originalUrl}`)
res.status(429).json({
message: "Too many requests, please try again later.",
});
}
});
if (req.originalUrl.includes("/api/")) {
return true;
}
return false;
},
handler: function (req, res, next) {
debugErrorLog(`Rate-limiting request: ip=${req.ip}, req=${req.originalUrl}`)
res.status(429).json({
message: "Too many requests, please try again later.",
});
}
});
// Apply the rate limiting middleware to all requests.
expressApp.use(rateLimiter);
// Apply the rate limiting middleware to all requests.
expressApp.use(rateLimiter);
}
if (config.baseUrl != '/') {

View file

@ -124,6 +124,11 @@ module.exports = {
baseUrl: cdnBaseUrl
},
rateLimiting: {
windowMinutes: process.env.BTCEXP_RATE_LIMIT_WINDOW_MINUTES || 15,
windowMaxRequests: process.env.BTCEXP_RATE_LIMIT_WINDOW_MAX_REQUESTS || 200
},
rpcBlacklist:
process.env.BTCEXP_RPC_ALLOWALL.toLowerCase() == "true" ? []
: process.env.BTCEXP_RPC_BLACKLIST ? process.env.BTCEXP_RPC_BLACKLIST.split(',').filter(Boolean)