Skip to content

Commit

Permalink
feat: support for rate limit whitelist
Browse files Browse the repository at this point in the history
  • Loading branch information
briananstett committed Dec 2, 2022
1 parent 1d789c4 commit 5bd1eac
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
27 changes: 27 additions & 0 deletions packages/rate-limit/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# @twentyfourg-express-sdk/rate-limit

[![Version](https://flat.badgen.net/npm/v/@twentyfourg-express-sdk/rate-limit)](https://github.com/twentyfourg/express-sdk/releases) [![Installs](https://flat.badgen.net/npm/dt/@twentyfourg-express-sdk/rate-limit)](https://www.npmjs.com/package/@twentyfourg-express-sdk/rate-limit)

Rate limiting middleware.

```javascript
router.post(
'/auth',
rateLimit({ max: 10, minutes: 1, keys: ['ip', 'body.email'] }),
validator.auth,
userController.auth
);
```

| Options | Description | Default |
| ----------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `minutes` | Time frame in minutes for which requests are checked/remembered. | `1` |
| `max` | The maximum number of connections to allow during the window before rate limiting the client. | `15` |
| `standardHeaders` | Whether to enable support for headers conforming to the ratelimit standardization draft. | `true` |
| `message` | `The response body to send back when a client is rate limited.` | `{ error: 'too many requests, please try again later' }` |
| `keys` | Which properties from the Express Request object to use in the rate limit composite key | `['ip', 'headers["user-agent"]']` |
| `whiteList` | List of IP addresses to whitelist | `SDK_EXPRESS_WHITE_LIST` environment variable |

## Environment Variables

| Variable | Description | Default |
| --------------------------------- | ------------------------------------------------------------------------------------ | ------- |
| `SDK_EXPRESS_WHITE_LIST` | String of IP addresses separated by commas to whitelist | `[]` |
| `EXPRESS_SDK_RATE_LIMIT_DISABLED` | Whether to disable rate limiting all together. Helpful for testing/dev environments. | `false` |
38 changes: 37 additions & 1 deletion packages/rate-limit/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,61 @@ const _ = require('lodash');
const rateLimit = require('express-rate-limit');
const DynamoStore = require('./dynamo.store');

/**
*
* @param {String} string String of to be to convert of a list
* @returns {Array<string>}
* @description Safely converts a string to a list. Useful for environment variables
*/
function stringToList(string) {
try {
return string.split(',');
} catch (error) {
return [];
}
}

/**
*
* @param {Object} opts Object for configuration
* @param {Number} [opts.minutes=1] Time frame in minutes for which requests are checked/remembered.
* @param {Number} [opts.max=15] The maximum number of connections to allow during the window before rate limiting the client.
* @param {Boolean} [opts.standardHeaders=true] Whether to enable support for headers conforming to the ratelimit standardization draft.
* @param {String || Object} [opts.message] The response body to send back when a client is rate limited.
* @param {Array<String>} [keys] Which properties from the Express Request object to use in the rate limit composite key
* @param {String} [whitelist=process.env.SDK_EXPRESS_WHITE_LIST] List of IP addresses to whitelist. Defaults to SDK_EXPRESS_WHITE_LIST or []
* @return {Function} Express middleware function
* @description Creates a rate limit Express Middleware function
*/
module.exports = (opts) => {
const defaults = {
minutes: 1,
max: 15,
standardHeaders: true,
message: { error: 'too many requests, please try again later' },
keys: ['ip', 'headers["user-agent"]'],
whiteList: stringToList(process.env.SDK_EXPRESS_WHITE_LIST),
};
const { minutes, name, ...options } = { ...defaults, ...opts };

if (process.env.EXPRESS_SDK_RATE_LIMIT_DISABLED === 'true') {
return (req, res, next) => {
next();
};
}
return rateLimit({
windowMs: minutes * 60 * 1000,
...options,
store: new DynamoStore(),
keyGenerator: (req /* , res */) => {
keyGenerator: (req) => {
const keys = name ? [name] : [req.method, req.originalUrl];
options.keys?.forEach((key) => {
if (_.get(req, key)) keys.push(_.get(req, key));
});
return keys.join(':');
},
skip: (req) => {
return options.whiteList.includes(req.ip);
},
});
};

0 comments on commit 5bd1eac

Please sign in to comment.