Installations
npm install rolling-rate-limiter-forked
Developer Guide
Typescript
No
Module System
CommonJS
NPM Version
1.4.18
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (98.86%)
JavaScript (1.14%)
Developer
classdojo
Download Statistics
Total Downloads
1,926
Last Day
1
Last Week
2
Last Month
15
Last Year
70
GitHub Statistics
348 Stars
107 Commits
53 Forks
29 Watching
2 Branches
16 Contributors
Bundle Size
2.09 kB
Minified
1.08 kB
Minified + Gzipped
Package Meta Information
Latest Version
0.2.0
Package Id
rolling-rate-limiter-forked@0.2.0
Size
5.18 kB
NPM Version
1.4.18
Total Downloads
Cumulative downloads
Total Downloads
1,926
Last day
0%
1
Compared to previous day
Last week
-60%
2
Compared to previous week
Last month
400%
15
Compared to previous month
Last year
-27.1%
70
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Rolling Rate Limiter
Description
This is an implementation of a rate limiter in node.js that allows for rate limiting with a rolling window.
This means that if a user is allowed 5 actions per 60 seconds, any action will be blocked if 5 actions have already occured in the preceeding 60 seconds, without any set points at which this interval resets. This contrasts with many existing implementations, in which a user could make 5 requests at 0:59 and another 5 requests at 1:01.
It can use either in-memory storage or Redis as a backend. If Redis is used, multiple rate limiters can share one instance with different namespaces, and multiple processes can share rate limiter state safely without race conditions. The implementation uses what I believe to be a novel algorithm, with sorted sets.
Examples
In-memory
1 2 /* 3 Setup: 4 */ 5 6 var RateLimiter = require("rolling-rate-limiter"); 7 8 var limiter = RateLimiter({ 9 interval: 1000 // in miliseconds 10 maxInInterval: 10 11 minDifference: 100 // optional: the minimum time (in miliseconds) between any two actions 12 }); 13 14 /* 15 Action: 16 */ 17 18 function attemptAction(userId) { 19 20 // Argument should be a unique identifier for a user if one exists. 21 // If none is provided, the limiter will not differentiate between users. 22 var timeLeft = limiter(userId) 23 24 if (timeLeft > 0) { 25 26 // limit was exceeded, action should not be allowed 27 // timeLeft is the number of ms until the next action will be allowed 28 // note that this can be treated as a boolean, since 0 is falsy 29 30 } else { 31 32 // limit was not exceeded, action should be allowed 33 34 } 35 36 } 37 38 /* 39 Note that the in-memory version can also operate asynchronously. 40 The syntax is identical to the redis implementation below. 41 */
With a redis backend
This allows multiple processes (e.g. multiple instances of a server application) to use a single redis to share rate limiter state. Make sure that the limiters have identical configurations in each instance.
1 2 /* 3 Setup: 4 */ 5 6 var RateLimiter = require("rolling-rate-limiter"); 7 var Redis = require("redis"); 8 var client = Redis.createClient(config); 9 10 var limiter = RateLimiter({ 11 redis: client, 12 namespace: "UserLoginLimiter" // optional: allows one redis instance to handle multiple types of rate limiters. defaults to "rate-limiter-{string of 8 random characters}" 13 interval: 1000 14 maxInInterval: 10 15 minDifference: 100 16 }); 17 18 /* 19 Action: 20 */ 21 22 function attemptAction(userId, cb) { 23 limiter(userId, function(err, timeLeft) { 24 if (err) { 25 // redis failed or similar. 26 } else if (timeLeft) { 27 // limit was exceeded, action should not be allowed 28 } else { 29 // limit was not exceeded, action should be allowed 30 } 31 }); 32 } 33
As a middleware
You can easily use this module to set up a request rate limiter middleware in Express.
1 var limiter = RateLimiter({ 2 redis: redisClient, 3 namespace: "requestRateLimiter", 4 interval: 60000, 5 maxInInterval: 100, 6 minDifference: 100 7 }); 8 9 app.use(function(req, res, next) { 10 11 // "req.ipAddress" could be replaced with any unique user identifier 12 // Note that the limiter returns the number of miliseconds until an action 13 // will be allowed. Since 0 is falsey, this can be treated as a boolean. 14 limiter(req.ipAddress, function(err, timeLeft) { 15 if (err) { 16 return res.status(500).send(); 17 } else if (timeLeft) { 18 return res.status(429).send("You must wait " + timeLeft + " ms before you can make requests."); 19 } else { 20 return next(); 21 } 22 }); 23 24 });
Method of operation
- Each identifier/user corresponds to a sorted set data structure. The keys and values are both equal to the (microsecond) times at which actions were attempted, allowing easy manipulation of this list.
- When a new action comes in for a user, all elements in the set that occurred earlier than (current time - interval) are dropped from the set.
- If the number of elements in the set is still greater than the maximum, the current action is blocked.
- If a minimum difference has been set and the most recent previous element is too close to the current time, the current action is blocked.
- The current action is then added to the set.
- Note: if an action is blocked, it is still added to the set. This means that if a user is continually attempting actions more quickly than the allowed rate, all of their actions will be blocked until they pause or slow their requests.
- If the limiter uses a redis instance, the keys are prefixed with namespace, allowing a single redis instance to support separate rate limiters.
- All redis operations for a single rate-limit check/update are performed as an atomic transaction, allowing rate limiters running on separate processes or machines to share state safely.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
Found 3/20 approved changesets -- score normalized to 1
Reason
9 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9
- Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/ci.yml:1
- Info: no jobLevel write permissions found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/peterkhayes/rolling-rate-limiter/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/peterkhayes/rolling-rate-limiter/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/peterkhayes/rolling-rate-limiter/ci.yml/master?enable=pin
- Info: 0 out of 2 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 third-party GitHubAction dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 13 are checked with a SAST tool
Score
2.7
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More