hapi plugin for IP based rate limiting. Simple and easy.
Switch branches/tags
Clone or download
Latest commit 0382988 Sep 30, 2018

README.md

hapi-rate-limitor logo

Solid and easy to use rate limiting for hapi.


Installation · Usage · Plugin Options · Route Options · Response Headers



Build Status Known Vulnerabilities hapi-rate-limitor Version

Follow @marcuspoehls for updates!


The Future Studio University supports development of this hapi plugin 🚀
Join the Future Studio University and Skyrocket in Node.js


Introduction

A hapi plugin to prevent brute-force attacks in your app. The rate limiter uses Redis to store rate-limit related data.

hapi-rate-limitor is built on top of these solid and awesome projects:

Each package solves its own problem perfectly. hapi-rate-limitor composes the solutions of each problem to a solid rate limit plugin for hapi.

Requirements

hapi v17 and Node.js v8 (or newer)

This plugin requires hapi v17 (or later) and uses async/await which requires Node.js v8 or newer.

Installation

Add hapi-rate-limitor as a dependency to your project:

# NPM v5 users, this way is yours
npm i hapi-rate-limitor

# you’re using NPM v4:
npm i -S hapi-rate-limitor

Usage

The most straight forward to use hapi-rate-limitor is to register it to your hapi server.

This will use the default configurations of async-ratelimiter and ioredis.

await server.register({
  plugin: require('hapi-rate-limitor')
})

// went smooth like chocolate with default settings :)

Plugin Options

Customize the plugin’s default configuration with the following options:

  • redis: (object), default: undefined — use the redis configuration to pass through your custom Redis configuration to ioredis
  • userAttribute: (string), default: 'id' — credentials property that identifies a user/request on dynamic rate limits. This option is used to access the value from request.auth.credentials.
  • userLimitAttribute: (string), default: 'rateLimit' — define the property name that identifies the rate limit value on dynamic rate limit. This option is used to access the value from request.auth.credentials.
  • view: (string), default: undefined — render the view instead of throwing an error (this uses h.view(yourView, { total, remaining, reset }).code(429))

All other options are directly passed through to async-ratelimiter.

await server.register({
  plugin: require('hapi-rate-limitor'),
  options: {
    redis: {
      port: 6379,
      host: '127.0.0.1'
    },
    namespace: 'hapi-rate-limitor',
    max: 2, // a maximum of 2 requests
    duration: 1000 // per second (the value is in milliseconds),
    userAttribute: 'id',
    userLimitAttribute: 'rateLimit',
    view: 'rate-limit-exceeded' // render this view when the rate limit exceeded
  }
})

// went smooth like chocolate :)

Please check the async-ratelimiter API for all options.

Route Options

Customize the plugin’s default configuration on routes. A use case for this is a login route where you want to reduce the request limit even lower than the default limit.

On routes, hapi-rate-limitor respects all options related to rate limiting. Precisely, all options that async-ratelimiter supports. It does not accept Redis connection options or identifiers for dynamic rate limiting.

All other options are directly passed through to async-ratelimiter.

await server.register({
  plugin: require('hapi-rate-limitor'),
  options: {
    redis: {
      port: 6379,
      host: '127.0.0.1'
    },
    namespace: 'hapi-rate-limitor',
    max: 60, // a maximum of 60 requests
    duration: 60 * 1000 // per minute (the value is in milliseconds)
  }
})

await server.route({
  method: 'POST',
  path: '/login',
  options: {
    handler: () {
      // do the login handling
    },
    plugins: {
      'hapi-rate-limitor': { // route config for `/login`
        max: 5, // a maximum of 5 requests
        duration: 60 * 1000 // per minute
      }
    }
  }
})

// went smooth like chocolate :)

Please check the async-ratelimiter API for all options.

Dynamic Rate Limits

To make use of user-specific rate limits, you need to configure the userIdKey and userLimitKey attributes in the hapi-rate-limitor options. These attributes are used to determine the rate limit properties. The userIdKey is the property name that uniquely identifies a user. The userLimitKey is the property name that contains the rate limit value.

await server.register({
  plugin: require('hapi-rate-limitor'),
  options: {
    userLimitId: 'id',
    userLimitKey: 'rateLimit',
    max: 500, // a maximum of 500 requests (default is 2500)
    duration: 60 * 60 * 1000 // per hour (the value is in milliseconds)
    // other plugin options
  }
})

This will calculate the maximum requests individually for each authenticated user based on the user’s id and 'rateLimit' attributes. Imagine the following user object as an authenticated user:

/**
 * the authenticated user object may contain
 * a custom rate limit attribute. In this
 * case, it's called "rateLimit".
 */
request.auth.credentials = {
  id: 'custom-uuid',
  rateLimit: 1750,
  name: 'Marcus'
  // ... further attributes
}

For this specific user, the maximum amount of requests is 1750 per hour (and not the plugin’s default 500).

hapi-rate-limitor uses the plugin’s limit if the request is unauthenticated or request.auth.credentials doesn’t contain a rate-limit-related attribute.

Response Headers

The plugin sets the following response headers:

  • X-Rate-Limit-Limit: total request limit (max) within duration
  • X-Rate-Limit-Remaining: remaining quota until reset
  • X-Rate-Limit-Reset: time since epoch in seconds that the rate limiting period will end

Feature Requests

Do you miss a feature? Please don’t hesitate to create an issue with a short description of your desired addition to this plugin.

Links & Resources

Contributing

  1. Create a fork
  2. Create your feature branch: git checkout -b my-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request 🚀

License

MIT © Future Studio


futurestud.io  ·  GitHub @fs-opensource  ·  Twitter @futurestud_io