Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

express-rate-limit

Package Overview
Dependencies
Maintainers
1
Versions
108
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-rate-limit - npm Package Compare versions

Comparing version 2.11.0 to 2.12.1

188

lib/express-rate-limit.js

@@ -1,110 +0,124 @@

'use strict';
var defaults = require('defaults');
var MemoryStore = require('./memory-store');
"use strict";
var defaults = require("defaults");
var MemoryStore = require("./memory-store");
function RateLimit(options) {
options = defaults(options, {
// window, delay, and max apply per-key unless global is set to true
windowMs: 60 * 1000, // milliseconds - how long to keep records of requests in memory
delayAfter: 1, // how many requests to allow through before starting to delay responses
delayMs: 1000, // milliseconds - base delay applied to the response - multiplied by number of recent hits for the same key.
max: 5, // max number of recent connections during `window` milliseconds before sending a 429 response
message : 'Too many requests, please try again later.',
statusCode: 429, // 429 status = Too Many Requests (RFC 6585)
headers: true, //Send custom rate limit header with limit and remaining
skipFailedRequests: false, // Do not count failed requests (status >= 400)
// allows to create custom keys (by default user IP is used)
keyGenerator: function (req /*, res*/) {
return req.ip;
options = defaults(options, {
// window, delay, and max apply per-key unless global is set to true
windowMs: 60 * 1000, // milliseconds - how long to keep records of requests in memory
delayAfter: 1, // how many requests to allow through before starting to delay responses
delayMs: 1000, // milliseconds - base delay applied to the response - multiplied by number of recent hits for the same key.
max: 5, // max number of recent connections during `window` milliseconds before sending a 429 response
message: "Too many requests, please try again later.",
statusCode: 429, // 429 status = Too Many Requests (RFC 6585)
headers: true, //Send custom rate limit header with limit and remaining
skipFailedRequests: false, // Do not count failed requests (status >= 400)
skipSuccessfulRequests: false, // Do not count successful requests (status < 400)
// allows to create custom keys (by default user IP is used)
keyGenerator: function(req /*, res*/) {
return req.ip;
},
skip: function(/*req, res*/) {
return false;
},
handler: function(req, res /*, next*/) {
if (options.headers) {
res.setHeader("Retry-After", Math.ceil(options.windowMs / 1000));
}
res.format({
html: function() {
res.status(options.statusCode).end(options.message);
},
skip: function (/*req, res*/) {
return false;
},
handler: function (req, res /*, next*/) {
if (options.headers) {
res.setHeader('Retry-After', Math.ceil(options.windowMs / 1000));
}
res.format({
html: function(){
res.status(options.statusCode).end(options.message);
},
json: function(){
res.status(options.statusCode).json({ message: options.message });
}
});
},
onLimitReached: function(/*req, res, optionsUsed*/) {}
});
json: function() {
res.status(options.statusCode).json({ message: options.message });
}
});
},
onLimitReached: function(/*req, res, optionsUsed*/) {}
});
// store to use for persisting rate limit data
options.store = options.store || new MemoryStore(options.windowMs);
// store to use for persisting rate limit data
options.store = options.store || new MemoryStore(options.windowMs);
// ensure that the store has the incr method
if (
typeof options.store.incr !== "function" ||
typeof options.store.resetKey !== "function" ||
(options.skipFailedRequests &&
typeof options.store.decrement !== "function")
) {
throw new Error("The store is not valid.");
}
// ensure that the store has the incr method
if (typeof options.store.incr !== 'function' || typeof options.store.resetKey !== 'function' ||
(options.skipFailedRequests && typeof options.store.decrement !== 'function')) {
throw new Error('The store is not valid.');
}
if (options.global) {
throw new Error(
"The global option was removed from express-rate-limit v2."
);
}
if (options.global) {
throw new Error('The global option was removed from express-rate-limit v2.');
function rateLimit(req, res, next) {
if (options.skip(req, res)) {
return next();
}
var key = options.keyGenerator(req, res);
function rateLimit(req, res, next) {
if (options.skip(req, res)) {
return next();
}
options.store.incr(key, function(err, current) {
if (err) {
return next(err);
}
var key = options.keyGenerator(req, res);
req.rateLimit = {
limit: options.max,
current: current,
remaining: Math.max(options.max - current, 0)
};
options.store.incr(key, function(err, current) {
if (err) {
return next(err);
}
if (options.headers) {
res.setHeader("X-RateLimit-Limit", options.max);
res.setHeader("X-RateLimit-Remaining", req.rateLimit.remaining);
}
req.rateLimit = {
limit: options.max,
current: current,
remaining: Math.max(options.max - current, 0)
};
if (options.max && current > options.max) {
options.onLimitReached(req, res, options);
return options.handler(req, res, next);
}
if (options.headers) {
res.setHeader('X-RateLimit-Limit', options.max);
res.setHeader('X-RateLimit-Remaining', req.rateLimit.remaining);
}
if (options.skipFailedRequests) {
res.on("finish", function() {
if (res.statusCode >= 400) {
options.store.decrement(key);
}
});
}
if (options.max && current > options.max) {
options.onLimitReached(req, res, options);
return options.handler(req, res, next);
}
if (options.skipSuccessfulRequests) {
res.on("finish", function() {
if (res.statusCode < 400) {
options.store.decrement(key);
}
});
}
if (options.skipFailedRequests) {
res.on('finish', function() {
if (res.statusCode >= 400) {
options.store.decrement(key);
}
});
}
if (
options.delayAfter &&
options.delayMs &&
current > options.delayAfter
) {
var delay = (current - options.delayAfter) * options.delayMs;
return setTimeout(next, delay);
}
if (options.delayAfter && options.delayMs && current > options.delayAfter) {
var delay = (current - options.delayAfter) * options.delayMs;
return setTimeout(next, delay);
}
next();
});
}
next();
rateLimit.resetKey = options.store.resetKey.bind(options.store);
});
}
// Backward compatibility function
rateLimit.resetIp = rateLimit.resetKey;
rateLimit.resetKey = options.store.resetKey.bind(options.store);
// Backward compatibility function
rateLimit.resetIp = rateLimit.resetKey;
return rateLimit;
return rateLimit;
}
module.exports = RateLimit;

@@ -1,2 +0,2 @@

'use strict';
"use strict";
function MemoryStore(windowMs) {

@@ -6,15 +6,15 @@ var hits = {};

this.incr = function(key, cb) {
if (hits[key]) {
hits[key]++;
} else {
hits[key] = 1;
}
if (hits[key]) {
hits[key]++;
} else {
hits[key] = 1;
}
cb(null, hits[key]);
cb(null, hits[key]);
};
this.decrement = function(key) {
if (hits[key]) {
hits[key]--;
}
if (hits[key]) {
hits[key]--;
}
};

@@ -24,3 +24,3 @@

this.resetAll = function() {
hits = {};
hits = {};
};

@@ -30,3 +30,3 @@

this.resetKey = function(key) {
delete hits[key];
delete hits[key];
};

@@ -33,0 +33,0 @@

{
"name": "express-rate-limit",
"version": "2.11.0",
"version": "2.12.1",
"description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",

@@ -38,17 +38,16 @@ "homepage": "https://github.com/nfriedly/express-rate-limit",

"devDependencies": {
"express": "^4.16.2",
"grunt": "^1.0.1",
"grunt-cli": "^1.0.0",
"grunt-contrib-jshint": "^1.1.0",
"grunt-contrib-nodeunit": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-mocha-cli": "^3.0.0",
"jshint-stylish": "^2.1.0",
"load-grunt-tasks": "^3.5.0",
"supertest": "^3.0.0",
"time-grunt": "^1.3.0"
"eslint": "^5.2.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-prettier": "^2.6.2",
"express": "^4.16.3",
"husky": "^0.14.3",
"mocha": "^5.2.0",
"prettier": "1.14.0",
"pretty-quick": "^1.6.0",
"supertest": "^3.1.0"
},
"scripts": {
"test": "grunt"
"test": "eslint . && mocha",
"precommit": "pretty-quick --staged"
}
}

@@ -11,5 +11,19 @@ # Express Rate Limit

Note: this module does not share state with other processes/servers by default.
If you need a more robust solution, I recommend adding the [Redis Store][rate-limit-redis] or checking out [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter), [express-brute](https://www.npmjs.com/package/express-brute), or [rate-limiter](https://www.npmjs.com/package/express-limiter) - all are excellent pieces of software.
If you need a more robust solution, I recommend using an addon store or trying out one of the excelent competing options.
### Stores
* Memory Store (default, built-in) - stores hits in-memory in the Node.js process. Does not share state with other servers or processes.
* [Redis Store][rate-limit-redis]
* [Memcached Store](https://npmjs.org/package/rate-limit-memcached)
### Alternate Rate-limiters
This module was designed to only handle the basics and didn't even support external stores initially. Thes other options all are excellent pieces of software and may be more appropriate for some situations:
* [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter)
* [express-brute](https://www.npmjs.com/package/express-brute)
* [rate-limiter](https://www.npmjs.com/package/express-limiter)
## Install

@@ -96,2 +110,3 @@

* **skipFailedRequests**: when `true` failed requests (response status >= 400) won't be counted. Defaults to `false`.
* **skipSuccessfulRequests**: when `true` successful requests (response status < 400) won't be counted. Defaults to `false`.
* **keyGenerator**: Function used to generate keys. By default user IP address (req.ip) is used. Defaults:

@@ -98,0 +113,0 @@ ```js

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc