Skip to content
This repository was archived by the owner on Apr 19, 2023. It is now read-only.

Commit 7006757

Browse files
✨ Add rate and speed limiting
1 parent d5a40ef commit 7006757

File tree

5 files changed

+89
-2
lines changed

5 files changed

+89
-2
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@types/dotenv": "^6.1.1",
3939
"@types/express": "^4.16.1",
4040
"@types/express-brute": "^0.0.37",
41+
"@types/express-slow-down": "^1.1.0",
4142
"@types/fs-extra": "^7.0.0",
4243
"@types/geolite2": "^1.2.0",
4344
"@types/hapi__joi": "^15.0.1",
@@ -78,6 +79,8 @@
7879
"express": "^4.17.0",
7980
"express-async-handler": "^1.1.4",
8081
"express-brute": "^1.0.1",
82+
"express-rate-limit": "^4.0.3",
83+
"express-slow-down": "^1.3.1",
8184
"fs-extra": "^8.0.1",
8285
"geolite2": "^1.2.1",
8386
"googleapis": "^40.0.0",

src/config.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@ config();
44
// Server
55
export const PORT = process.env.PORT ? parseInt(process.env.PORT) : 7007;
66
export const SENTRY_DSN = process.env.SENTRY_DSN || "";
7+
8+
// Rate limiting
79
export const BRUTE_FREE_RETRIES = process.env.BRUTE_FREE_RETRIES
810
? parseInt(process.env.BRUTE_FREE_RETRIES)
911
: 10;
1012
export const BRUTE_LIFETIME = process.env.BRUTE_LIFETIME
1113
? parseInt(process.env.BRUTE_LIFETIME)
1214
: 300000;
15+
export const RATE_LIMIT_TIME = process.env.RATE_LIMIT_TIME
16+
? parseInt(process.env.RATE_LIMIT_TIME)
17+
: 60000; // 1 minute
18+
export const RATE_LIMIT_MAX = process.env.RATE_LIMIT_MAX
19+
? parseInt(process.env.RATE_LIMIT_MAX)
20+
: 200; // Max 200 requests/minute from an IP
21+
export const SPEED_LIMIT_TIME = process.env.SPEED_LIMIT_TIME
22+
? parseInt(process.env.SPEED_LIMIT_TIME)
23+
: 600000; // 10 minutes
24+
export const SPEED_LIMIT_DELAY = process.env.SPEED_LIMIT_DELAY
25+
? parseInt(process.env.SPEED_LIMIT_DELAY)
26+
: 100; // 100ms per request delay
27+
export const SPEED_LIMIT_COUNT = process.env.SPEED_LIMIT_COUNT
28+
? parseInt(process.env.SPEED_LIMIT_COUNT)
29+
: 1000; // Start delaying after 1000 requests
1330

1431
// Database
1532
export const DB_HOST = process.env.DB_HOST || "localhost";

src/helpers/middleware.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
import { Request, Response, NextFunction } from "express";
22
import Brute from "express-brute";
3+
import { RateLimit } from "express-rate-limit";
4+
import slowDown from "express-slow-down";
35
import { safeError } from "./errors";
46
import { verifyToken } from "./jwt";
57
import { ErrorCode, Tokens } from "../interfaces/enum";
6-
import { BRUTE_LIFETIME, BRUTE_FREE_RETRIES } from "../config";
8+
import {
9+
BRUTE_LIFETIME,
10+
BRUTE_FREE_RETRIES,
11+
RATE_LIMIT_MAX,
12+
RATE_LIMIT_TIME,
13+
SPEED_LIMIT_DELAY,
14+
SPEED_LIMIT_COUNT,
15+
SPEED_LIMIT_TIME
16+
} from "../config";
717
const store = new Brute.MemoryStore();
818
const bruteForce = new Brute(store, {
919
freeRetries: BRUTE_FREE_RETRIES,
1020
lifetime: BRUTE_LIFETIME
1121
});
22+
const rateLimiter = RateLimit({
23+
windowMs: RATE_LIMIT_TIME,
24+
max: RATE_LIMIT_MAX
25+
});
26+
const speedLimiter = slowDown({
27+
windowMs: SPEED_LIMIT_TIME,
28+
delayAfter: SPEED_LIMIT_COUNT,
29+
delayMs: SPEED_LIMIT_DELAY
30+
});
1231

1332
/**
1433
* Handle any errors for Express
@@ -75,3 +94,13 @@ export const authHandler = async (
7594
* Brute force middleware
7695
*/
7796
export const bruteForceHandler = bruteForce.prevent;
97+
98+
/**
99+
* Rate limiting middleware
100+
*/
101+
export const rateLimitHandler = rateLimiter;
102+
103+
/**
104+
* Speed limiting middleware
105+
*/
106+
export const speedLimitHandler = speedLimiter;

src/server.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import responseTime from "response-time";
77
import { json, urlencoded } from "body-parser";
88
import { Server } from "@overnightjs/core";
99
import { UserController } from "./controllers/user";
10-
import { errorHandler, trackingHandler } from "./helpers/middleware";
10+
import {
11+
errorHandler,
12+
trackingHandler,
13+
rateLimitHandler,
14+
speedLimitHandler
15+
} from "./helpers/middleware";
1116
import { OrganizationController } from "./controllers/organization";
1217
import { AdminController } from "./controllers/admin";
1318
import { AuthController } from "./controllers/auth";
@@ -38,6 +43,8 @@ export class Staart extends Server {
3843
this.app.use(urlencoded({ extended: true }));
3944
this.app.use(responseTime());
4045
this.app.use(trackingHandler);
46+
this.app.use(rateLimitHandler);
47+
this.app.use(speedLimitHandler);
4148
}
4249

4350
private setupControllers() {

yarn.lock

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,13 @@
11211121
"@types/node" "*"
11221122
"@types/range-parser" "*"
11231123

1124+
"@types/express-slow-down@^1.1.0":
1125+
version "1.1.0"
1126+
resolved "https://registry.yarnpkg.com/@types/express-slow-down/-/express-slow-down-1.1.0.tgz#bbca86683d86dc21d740aa6e336fba4dc1e77309"
1127+
integrity sha512-216eW7oONH1L1dddDO4cv9bdZzakSJylBxC3Yxkx6j8k4bc/c8PSlszIFq7yKQHqeA1vloyxAc50qwTxUGCTqg==
1128+
dependencies:
1129+
"@types/express" "*"
1130+
11241131
"@types/express@*", "@types/express@^4.16.1":
11251132
version "4.16.1"
11261133
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0"
@@ -1978,6 +1985,11 @@ clone@2.x:
19781985
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
19791986
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
19801987

1988+
clone@^1.0.2:
1989+
version "1.0.4"
1990+
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
1991+
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
1992+
19811993
co@^4.6.0:
19821994
version "4.6.0"
19831995
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -2289,6 +2301,13 @@ deep-is@~0.1.3:
22892301
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
22902302
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
22912303

2304+
defaults@^1.0.3:
2305+
version "1.0.3"
2306+
resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
2307+
integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
2308+
dependencies:
2309+
clone "^1.0.2"
2310+
22922311
define-properties@^1.1.2:
22932312
version "1.1.3"
22942313
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -2605,6 +2624,18 @@ express-brute@^1.0.1:
26052624
long-timeout "~0.1.1"
26062625
underscore "~1.8.3"
26072626

2627+
express-rate-limit@^4.0.3:
2628+
version "4.0.3"
2629+
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.3.tgz#70ec815f6ba2d6a62400c8a7bd341c420b4330cc"
2630+
integrity sha512-9+v6DXQdLLd4EqdEkXXM1ctdVNgjw4w8V1WLvlpnIb2SZ5wJ3Kvu8FOMzBPIAX+iO1F24AG640eOOHCv/0GmKg==
2631+
2632+
express-slow-down@^1.3.1:
2633+
version "1.3.1"
2634+
resolved "https://registry.yarnpkg.com/express-slow-down/-/express-slow-down-1.3.1.tgz#0458bb8670ea1cbedaa00bae4293024ee4e9445e"
2635+
integrity sha512-mkxVJt3z2e0/LIVp144xpaPw8Ku2f6XS9ftjgwMsUtp+4a84hk6NI6/KTEPkq1kjCsJuXeG6SA/izCWxaErBdg==
2636+
dependencies:
2637+
defaults "^1.0.3"
2638+
26082639
express@^4.16.3, express@^4.17.0:
26092640
version "4.17.1"
26102641
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"

0 commit comments

Comments
 (0)