-
-
Notifications
You must be signed in to change notification settings - Fork 182
Hapi plugin
Roman edited this page Nov 10, 2023
·
6 revisions
'use strict';
const Boom = require('boom');
const redis = require('ioredis');
const {RateLimiterRedis} = require('rate-limiter-flexible');
const internals = {
pluginName: 'rateLimitRedisPlugin',
};
internals.redisClient = new Redis({
host: 'redis',
port: 6379,
enableOfflineQueue: false,
});
internals.rateLimiter = new RateLimiterRedis({
storeClient: internals.redisClient,
keyPrefix: 'hapi-plugin',
points: 10, // 10 requests
duration: 1, // per 1 second by IP
});
module.exports = {
name: internals.pluginName,
version: '1.0.0',
register: function (server) {
server.ext('onPreAuth', async (request, h) => {
try {
await internals.rateLimiter.consume(request.info.remoteAddress);
return h.continue;
} catch (rej) {
let error;
if (rej instanceof Error) {
// If some Redis error and `insuranceLimiter` is not set
error = Boom.internal('Try later');
} else {
// Not enough points to consume
error = Boom.tooManyRequests('Rate limit exceeded');
error.output.headers['Retry-After'] = Math.round(rej.msBeforeNext / 1000) || 1;
}
return error;
}
});
}
};onPreAuth event is used to rate limit requests for all application routes. Depending on requirements you may use onPostAuth, onPostHandler, etc (read about request lifecycle in official hapi docs)
'use strict';
const Hapi = require('hapi');
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello, world!';
}
});
const init = async () => {
await server.register(require('./plugin/rateLimitRedis'));
await server.start();
};
process.on('unhandledRejection', (err) => {
process.exit(1);
});
init();Mongo, Memcached, MySQL or any other limiter from this package can be used with the same approach.
Get started
Middlewares and plugins
Migration from other packages
Limiters:
- Cluster
- Drizzle
- DynamoDB
- Etcd
- Memcached
- Memory
- MongoDB (with sharding support)
- MySQL
- PM2 Cluster
- PostgreSQL
- Prisma
- Redis
- SQLite
- Valkey: iovalkey and Valkey Glide
- BurstyRateLimiter
- RateLimiterUnion
- RateLimiterQueue
Wrappers:
- AWS SDK v3 Client Rate Limiter
- RLWrapperBlackAndWhite Black and White lists
- RLWrapperTimeouts Timeouts
Knowledge base:
- Block Strategy in memory
- Insurance Strategy
- Periodic sync to reduce number of requests
- Comparative benchmarks
- Smooth out traffic peaks
-
Usage example
- Minimal protection against password brute-force
- Login endpoint protection
- Websocket connection prevent flooding
- Dynamic block duration
- Different limits for authorized users
- Different limits for different parts of application
- Block Strategy in memory
- Insurance Strategy
- Third-party API, crawler, bot rate limiting