DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

64 lines
1.8 KiB

// limiter.js
// Copyright (C) 2024 DTP Technologies, LLC
// All Rights Reserved
'use strict';
import path from 'node:path';
import expressLimiter from 'express-limiter';
import { SiteService, SiteError } from '../../lib/site-lib.js';
export default class LimiterService extends SiteService {
static get slug ( ) { return 'limiter'; }
static get name ( ) { return 'LimiterService'; }
constructor (dtp) {
super(dtp, LimiterService);
this.handlers = {
lookup: this.limiterLookup.bind(this),
whitelist: this.limiterWhitelist.bind(this),
};
}
async start ( ) {
this.config = (await import(path.resolve(this.dtp.config.root, 'config', 'limiter.js'))).default;
this.limiter = expressLimiter(this.dtp.app, this.dtp.redis);
}
create (config) {
const options = {
total: config.total,
expire: config.expire,
lookup: this.handlers.lookup,
whitelist: this.handlers.whitelist,
onRateLimited: async (req, res, next) => {
this.emit('limiter:block', req);
next(new SiteError(config.status || 429, config.message || 'Rate limit exceeded'));
},
};
// this.log.debug('creating rate limiter', { options });
const middleware = this.limiter(options);
return async (req, res, next) => {
return middleware(req, res, next);
};
}
limiterLookup (req, res, options, next) {
if (req.user) {
options.lookup = 'user._id'; // req.user._id, populated by PassportJS session
} else {
options.lookup = 'ip'; // req.ip, populated by ExpressJS with trust_proxy=1
}
return next();
}
limiterWhitelist (req) {
if ((process.env.NODE_ENV === 'local') && (process.env.DTP_RATE_LIMITER === 'disabled')) {
return true;
}
return req.user && req.user.flags.isAdmin;
}
}