const {RateLimiterPostgres, RateLimiterUnion} = require('rate-limiter-flexible'); const pg = require('../../db/pg') const globalOptions = { storeClient: pg, tableName: 'sos.rate_limits', tableCreated: true } function createRateLimit(maxTimes, duration, prefix) { return new RateLimiterPostgres({ ...globalOptions, points: maxTimes, inmemoryBlockOnConsumed: maxTimes, keyPrefix: prefix, duration }) } module.exports = {}; const loginRateLimits = [ // Once per ten seconds createRateLimit(1, 10, 'logon1'), // Ten tries in five minutes createRateLimit(10, 5 * 60, 'logon2'), // One hundred in a day createRateLimit(100, 24 * 60 * 60, 'logon3') ] const loginRateLimitPool = new RateLimiterUnion(...loginRateLimits) module.exports.loginRateLimit = async (req, res) => { try { await loginRateLimitPool.consume(req.body.email) return 'next'; } catch (limits) { const wait = Math.max(...Object.values(limits).map(limit => limit?.msBeforeNext || 1)); res.status(429) res.set({ 'Retry-After': Math.ceil(wait / 1000) }) res.json({errors: [{ param: 'email', msg: `Too many password attempts, please wait ${Math.ceil(wait / 1000)} seconds` },{ param: 'password', msg: ' ' }]}) } } module.exports.loginRateLimit.reset = email => Promise.all( loginRateLimits.map(rateLimit => rateLimit.delete(email) ) )