-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathsliding-window-log.ts
74 lines (59 loc) · 1.99 KB
/
sliding-window-log.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { NextFunction, Request, Response } from 'express';
import { RateLimiter, SlidingWindowLogArgs } from '../types';
const MAX_LOG_THRESHOLD = 100; // Maximum number of requests per second
const MIN_LOG_THRESHOLD = 1; // Minimum number of requests per second
export class SlidingWindowLogRateLimiter implements RateLimiter {
/**
* Stores the timestamp for each IP.
*
* @type {Map<string, Date[]>}
*/
logs: Map<string, Date[]>;
logThreshold: number;
constructor({ logThreshold }: SlidingWindowLogArgs) {
this.logs = new Map<string, Date[]>();
// Validate logThreshold value
if (
logThreshold >= MIN_LOG_THRESHOLD &&
logThreshold <= MAX_LOG_THRESHOLD
) {
this.logThreshold = logThreshold;
} else {
throw new Error(
`logThreshold should be between ${MIN_LOG_THRESHOLD} and ${MAX_LOG_THRESHOLD}`
);
}
}
handleRequest(req: Request, res: Response, next: NextFunction) {
const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
// Make sure a valid IP is present in the request.
if (typeof ip !== 'string') {
res
.status(400)
.send('Invalid x-forwarded-for header or remote address\n');
return;
}
const date = new Date();
const log = this.logs.get(ip);
// First request for the IP
if (log === undefined) {
this.logs.set(ip, [date]);
next();
return;
}
// The requests before timeWindowFront will be discarded
const timeWindowFront = date.getTime() - 1000; // 1 second less
const newLog = log.filter((value) => value.getTime() > timeWindowFront);
// Check if size of newLog is greater than the specified threshold
if (newLog.length >= this.logThreshold) {
res.status(429).send('Too many requests. Please try again later!\n');
return;
}
// Add the new log entry for this request
newLog.push(date);
// Update the logs for this IP
this.logs.set(ip, newLog);
next();
}
cleanup(): void {}
}