Skip to content

Commit c79f38e

Browse files
authored
feat: add IP allowlist and blocklist support [ GSSOC'26 ] (JhaSourav07#1199)
## Description Added allowlist and blocklist support to the `RateLimiter` class via `allow()`, `block()`, `unallow()`, and `unblock()` methods. Allowlisted IPs always pass, blocklisted IPs are always denied — both bypass the counter logic in `check()` and `checkWithResult()`. Useful for trusted internal services and known bad actors. Fixes JhaSourav07#1196 ## Pillar - [ ] 🎨 Pillar 1 — New Theme Design - [ ] 📐 Pillar 2 — Geometric SVG Improvement - [ ] 🕐 Pillar 3 — Timezone Logic Optimization - [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview N/A — internal utility methods, no visual output. ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally (`localhost:3000/api/streak?user=YOUR_USERNAME`). - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). - [x] My commits follow the Conventional Commits format (e.g., `feat(rate-limiter): ...`). - [ ] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have starred the repo. - [x] I have made sure that I have only one commit to merge in this PR. - [ ] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no raw elements, smooth animations, correct fonts). - [ ] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents caa4798 + b6ca706 commit c79f38e

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

lib/rate-limit.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export class RateLimiter {
1818
private cache: TTLCache<number>;
1919
private limit: number;
2020
private windowMs: number;
21+
private allowlist = new Set<string>();
22+
private blocklist = new Set<string>();
2123

2224
/**
2325
* Creates a new RateLimiter instance.
@@ -46,6 +48,8 @@ export class RateLimiter {
4648
* }
4749
*/
4850
check(ip: string): boolean {
51+
if (this.allowlist.has(ip)) return true; // for check()
52+
if (this.blocklist.has(ip)) return false; // for check()
4953
const current = this.cache.get(ip) || 0;
5054
if (current >= this.limit) {
5155
return false;
@@ -54,6 +58,15 @@ export class RateLimiter {
5458
return true;
5559
}
5660
checkWithResult(ip: string): RateLimitResult {
61+
if (this.allowlist.has(ip))
62+
return {
63+
success: true,
64+
limit: this.limit,
65+
remaining: this.limit,
66+
reset: Date.now() + this.windowMs,
67+
};
68+
if (this.blocklist.has(ip))
69+
return { success: false, limit: this.limit, remaining: 0, reset: Date.now() + this.windowMs };
5770
const now = Date.now();
5871
const current = this.cache.get(ip) ?? 0;
5972

@@ -88,6 +101,24 @@ export class RateLimiter {
88101
reset(ip: string): void {
89102
this.cache.delete(ip);
90103
}
104+
105+
allow(ip: string): void {
106+
this.allowlist.add(ip);
107+
this.blocklist.delete(ip);
108+
}
109+
110+
block(ip: string): void {
111+
this.blocklist.add(ip);
112+
this.allowlist.delete(ip);
113+
}
114+
115+
unallow(ip: string): void {
116+
this.allowlist.delete(ip);
117+
}
118+
119+
unblock(ip: string): void {
120+
this.blocklist.delete(ip);
121+
}
91122
}
92123

93124
// Global instance for track-user endpoint (5 requests per IP per minute)

0 commit comments

Comments
 (0)