From 82446cb37ac7955d0209af64c55f4953ebe67a00 Mon Sep 17 00:00:00 2001 From: Nikhil Dange Date: Wed, 14 Feb 2024 17:36:01 -0800 Subject: [PATCH 1/5] removed other changes and added rate limit logic --- api/middleware/RateLimiter.ts | 22 ++++++++++++++++++++++ api/middleware/index.ts | 2 ++ index.ts | 2 ++ package.json | 1 + yarn.lock | 5 +++++ 5 files changed, 32 insertions(+) create mode 100644 api/middleware/RateLimiter.ts diff --git a/api/middleware/RateLimiter.ts b/api/middleware/RateLimiter.ts new file mode 100644 index 00000000..eb076e71 --- /dev/null +++ b/api/middleware/RateLimiter.ts @@ -0,0 +1,22 @@ +import { ExpressMiddlewareInterface, Middleware } from 'routing-controllers'; + import * as express from 'express'; + import { rateLimit } from 'express-rate-limit'; + // import { Config } from '../../config'; + + @Middleware({ type: 'before' }) + export class RateLimiter implements ExpressMiddlewareInterface { + private limiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 5, + message: 'Too many requests, please try again later.', + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers + }); + + use(req: express.Request, res: express.Response, next: express.NextFunction) { + if (req.path === '/api/v2/user') { + return this.limiter(req, res, next); + } + return next(); + } +} \ No newline at end of file diff --git a/api/middleware/index.ts b/api/middleware/index.ts index 8907e8f0..d7858c11 100644 --- a/api/middleware/index.ts +++ b/api/middleware/index.ts @@ -2,10 +2,12 @@ import { RequestLogger } from './RequestLogger'; import { ErrorHandler } from './ErrorHandler'; import { NotFoundHandler } from './NotFoundHandler'; import { MetricsRecorder } from './MetricsRecorder'; +import { RateLimiter } from './RateLimiter'; export const middlewares = [ ErrorHandler, NotFoundHandler, RequestLogger, MetricsRecorder, + RateLimiter ]; diff --git a/index.ts b/index.ts index ed1aafff..3dd1a1e4 100644 --- a/index.ts +++ b/index.ts @@ -53,4 +53,6 @@ const app = createExpressServer({ defaultErrorHandler: false, }); +app.set('trust proxy', 1); + app.listen(Config.port); diff --git a/package.json b/package.json index 39b41095..54ee81ec 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "dotenv": "^8.2.0", "ejs": "^3.1.3", "express": "^4.17.1", + "express-rate-limit": "6.11.2", "faker": "^5.5.3", "jsonwebtoken": "^8.5.1", "moment": "^2.27.0", diff --git a/yarn.lock b/yarn.lock index 400edfbf..2ba706b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2373,6 +2373,11 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +express-rate-limit@6.11.2: + version "6.11.2" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.11.2.tgz#6c42035603d3b52e4e2fb59f6ebaa89e628ef980" + integrity sha512-a7uwwfNTh1U60ssiIkuLFWHt4hAC5yxlLGU2VP0X4YNlyEDZAqF4tK3GD3NSitVBrCQmQ0++0uOyFOgC2y4DDw== + express-session@^1.17.1: version "1.17.2" resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.2.tgz#397020374f9bf7997f891b85ea338767b30d0efd" From 84946100356854bcd99df68efc20c959a8fae6dd Mon Sep 17 00:00:00 2001 From: Nikhil Dange Date: Sat, 24 Feb 2024 12:14:13 -0800 Subject: [PATCH 2/5] idk what im doing --- api/controllers/UserController.ts | 1 + api/decorators/RateLimit.ts | 21 +++++++++++++++++++++ api/middleware/index.ts | 4 ++-- 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 api/decorators/RateLimit.ts diff --git a/api/controllers/UserController.ts b/api/controllers/UserController.ts index e80f4347..2e90051c 100644 --- a/api/controllers/UserController.ts +++ b/api/controllers/UserController.ts @@ -7,6 +7,7 @@ import UserSocialMediaService from '../../services/UserSocialMediaService'; import StorageService from '../../services/StorageService'; import { UserAuthentication } from '../middleware/UserAuthentication'; import { AuthenticatedUser } from '../decorators/AuthenticatedUser'; +import { RateLimited } from '../decorators/RateLimit'; import { MediaType, File, diff --git a/api/decorators/RateLimit.ts b/api/decorators/RateLimit.ts new file mode 100644 index 00000000..5ad2a6ff --- /dev/null +++ b/api/decorators/RateLimit.ts @@ -0,0 +1,21 @@ +import { createParamDecorator } from 'routing-controllers'; +import RateLimit from 'express-rate-limit'; + +// Define your rate limit options +const rateLimitOptions = { + windowMs: 15 * 60 * 1000, // 15 minutes + max: 1, // limit each IP to 100 requests per windowMs +}; + +// Create a rate limiter instance +const limiter = RateLimit(rateLimitOptions); + +// Define a decorator function to apply rate limiting +export function RateLimited() { + return createParamDecorator({ + value: async ({ context }) => { + await limiter(context.req, context.res, () => {}); + return true; // Or any other value you need + }, + }); +} \ No newline at end of file diff --git a/api/middleware/index.ts b/api/middleware/index.ts index d7858c11..b49b06bc 100644 --- a/api/middleware/index.ts +++ b/api/middleware/index.ts @@ -2,12 +2,12 @@ import { RequestLogger } from './RequestLogger'; import { ErrorHandler } from './ErrorHandler'; import { NotFoundHandler } from './NotFoundHandler'; import { MetricsRecorder } from './MetricsRecorder'; -import { RateLimiter } from './RateLimiter'; +// import { RateLimiter } from './RateLimiter'; export const middlewares = [ ErrorHandler, NotFoundHandler, RequestLogger, MetricsRecorder, - RateLimiter + // RateLimiter ]; From 3a3e8fceac0529788cd0945883af24461a7d4050 Mon Sep 17 00:00:00 2001 From: Nikhil Dange Date: Mon, 26 Feb 2024 17:12:19 -0800 Subject: [PATCH 3/5] idk --- api/decorators/RateLimit.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/decorators/RateLimit.ts b/api/decorators/RateLimit.ts index 5ad2a6ff..5b87ce5a 100644 --- a/api/decorators/RateLimit.ts +++ b/api/decorators/RateLimit.ts @@ -14,8 +14,8 @@ const limiter = RateLimit(rateLimitOptions); export function RateLimited() { return createParamDecorator({ value: async ({ context }) => { - await limiter(context.req, context.res, () => {}); + limiter(context.req, context.res, () => { }); return true; // Or any other value you need }, }); -} \ No newline at end of file +} From d7ac9f18c7480d61195aecdd4e909c4d38082023 Mon Sep 17 00:00:00 2001 From: Nikhil Dange Date: Sat, 9 Mar 2024 13:26:03 -0800 Subject: [PATCH 4/5] i hate this --- api/controllers/AdminController.ts | 4 ++++ api/controllers/UserController.ts | 2 +- api/decorators/RateLimit.ts | 38 +++++++++++++++--------------- api/middleware/RateLimiter.ts | 5 +--- api/middleware/index.ts | 4 ++-- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/api/controllers/AdminController.ts b/api/controllers/AdminController.ts index 6ab76108..4cb540db 100644 --- a/api/controllers/AdminController.ts +++ b/api/controllers/AdminController.ts @@ -1,5 +1,6 @@ import { JsonController, Post, Patch, UploadedFile, UseBefore, ForbiddenError, Body, Get } from 'routing-controllers'; import { UserAuthentication } from '../middleware/UserAuthentication'; +import { RateLimiter } from '../middleware/RateLimiter'; import { CreateBonusRequest, CreateMilestoneRequest, @@ -23,6 +24,7 @@ import StorageService from '../../services/StorageService'; import PermissionsService from '../../services/PermissionsService'; import { UserModel } from '../../models/UserModel'; import AttendanceService from '../../services/AttendanceService'; +import { RateLimit } from '../decorators/RateLimit'; @UseBefore(UserAuthentication) @JsonController('/admin') @@ -40,7 +42,9 @@ export class AdminController { this.attendanceService = attendanceService; } + @Get('/email') + @UseBefore(RateLimiter) async getAllEmails(@AuthenticatedUser() user: UserModel): Promise { if (!PermissionsService.canSeeAllUserEmails(user)) throw new ForbiddenError(); const emails = await this.userAccountService.getAllEmails(); diff --git a/api/controllers/UserController.ts b/api/controllers/UserController.ts index 2e90051c..e7a93004 100644 --- a/api/controllers/UserController.ts +++ b/api/controllers/UserController.ts @@ -7,7 +7,7 @@ import UserSocialMediaService from '../../services/UserSocialMediaService'; import StorageService from '../../services/StorageService'; import { UserAuthentication } from '../middleware/UserAuthentication'; import { AuthenticatedUser } from '../decorators/AuthenticatedUser'; -import { RateLimited } from '../decorators/RateLimit'; +import { RateLimit } from '../decorators/RateLimit'; import { MediaType, File, diff --git a/api/decorators/RateLimit.ts b/api/decorators/RateLimit.ts index 5b87ce5a..55b90d02 100644 --- a/api/decorators/RateLimit.ts +++ b/api/decorators/RateLimit.ts @@ -1,21 +1,21 @@ -import { createParamDecorator } from 'routing-controllers'; -import RateLimit from 'express-rate-limit'; +import rateLimit from 'express-rate-limit'; -// Define your rate limit options -const rateLimitOptions = { - windowMs: 15 * 60 * 1000, // 15 minutes - max: 1, // limit each IP to 100 requests per windowMs -}; - -// Create a rate limiter instance -const limiter = RateLimit(rateLimitOptions); - -// Define a decorator function to apply rate limiting -export function RateLimited() { - return createParamDecorator({ - value: async ({ context }) => { - limiter(context.req, context.res, () => { }); - return true; // Or any other value you need - }, +export function RateLimit(limit: number): MethodDecorator { + const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: limit, + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers }); -} + + return function (_target: any, _key: string, descriptor: PropertyDescriptor) { + const originalMethod = descriptor.value; + console.log("originalMethod", originalMethod); + descriptor.value = function (...args: any[]) { + const context = args[0]; + limiter(context.req, context.res, () => {}); + return originalMethod.apply(this, args); + }; + return descriptor; + }; +} \ No newline at end of file diff --git a/api/middleware/RateLimiter.ts b/api/middleware/RateLimiter.ts index eb076e71..d335d35b 100644 --- a/api/middleware/RateLimiter.ts +++ b/api/middleware/RateLimiter.ts @@ -14,9 +14,6 @@ import { ExpressMiddlewareInterface, Middleware } from 'routing-controllers'; }); use(req: express.Request, res: express.Response, next: express.NextFunction) { - if (req.path === '/api/v2/user') { - return this.limiter(req, res, next); - } - return next(); + return this.limiter(req, res, next); } } \ No newline at end of file diff --git a/api/middleware/index.ts b/api/middleware/index.ts index b49b06bc..d7858c11 100644 --- a/api/middleware/index.ts +++ b/api/middleware/index.ts @@ -2,12 +2,12 @@ import { RequestLogger } from './RequestLogger'; import { ErrorHandler } from './ErrorHandler'; import { NotFoundHandler } from './NotFoundHandler'; import { MetricsRecorder } from './MetricsRecorder'; -// import { RateLimiter } from './RateLimiter'; +import { RateLimiter } from './RateLimiter'; export const middlewares = [ ErrorHandler, NotFoundHandler, RequestLogger, MetricsRecorder, - // RateLimiter + RateLimiter ]; From 58cc2140ce07ece4eebd9d4fe00e40c8709d3d3d Mon Sep 17 00:00:00 2001 From: Nikhil Dange Date: Sat, 9 Mar 2024 13:54:40 -0800 Subject: [PATCH 5/5] crying --- api/controllers/AdminController.ts | 2 +- api/decorators/RateLimit.ts | 16 +++++++++------- api/middleware/index.ts | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/api/controllers/AdminController.ts b/api/controllers/AdminController.ts index 4cb540db..6fe30da9 100644 --- a/api/controllers/AdminController.ts +++ b/api/controllers/AdminController.ts @@ -44,7 +44,7 @@ export class AdminController { @Get('/email') - @UseBefore(RateLimiter) + @RateLimit() async getAllEmails(@AuthenticatedUser() user: UserModel): Promise { if (!PermissionsService.canSeeAllUserEmails(user)) throw new ForbiddenError(); const emails = await this.userAccountService.getAllEmails(); diff --git a/api/decorators/RateLimit.ts b/api/decorators/RateLimit.ts index 55b90d02..b022ba78 100644 --- a/api/decorators/RateLimit.ts +++ b/api/decorators/RateLimit.ts @@ -1,13 +1,15 @@ import rateLimit from 'express-rate-limit'; -export function RateLimit(limit: number): MethodDecorator { - const limiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: limit, - standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers - legacyHeaders: false, // Disable the `X-RateLimit-*` headers - }); +const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 5, + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers +}); +console.log("HELLO"); + +export function RateLimit(): MethodDecorator { return function (_target: any, _key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; console.log("originalMethod", originalMethod); diff --git a/api/middleware/index.ts b/api/middleware/index.ts index d7858c11..5c13b78d 100644 --- a/api/middleware/index.ts +++ b/api/middleware/index.ts @@ -2,12 +2,12 @@ import { RequestLogger } from './RequestLogger'; import { ErrorHandler } from './ErrorHandler'; import { NotFoundHandler } from './NotFoundHandler'; import { MetricsRecorder } from './MetricsRecorder'; -import { RateLimiter } from './RateLimiter'; +//import { RateLimiter } from './RateLimiter'; export const middlewares = [ ErrorHandler, NotFoundHandler, RequestLogger, MetricsRecorder, - RateLimiter + //RateLimiter ];