From c330737bff62bb15c217a37e61339ff407a7e49d Mon Sep 17 00:00:00 2001 From: d3v53c Date: Thu, 29 Oct 2020 00:23:00 -0700 Subject: [PATCH 1/5] Raised 401 instead of 404 when email not found --- api/src/services/user.service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 70569501..92ea3868 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -181,7 +181,10 @@ export class UserService { async authenticate({ grantType, email, password }: { grantType: GrantType; email: string; password?: string }): Promise { const normalizedEmail = normalizeEmail(email); - const user = await this.userRepo.findOneOrFail({ email: normalizedEmail }); + const user = await this.userRepo.findOne({ email: normalizedEmail }); + if (!user) { + throw new UnauthorizedException('invalid credentials'); + } const timeThreshold = moment() .subtract(15, 'minutes') From 0a66ed354befeb421d879a92a8c4c1494c8c74cc Mon Sep 17 00:00:00 2001 From: Arjun Shibu Date: Wed, 4 Nov 2020 10:08:06 +0530 Subject: [PATCH 2/5] Update package.json --- api/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/api/package.json b/api/package.json index d1be7252..ca377285 100644 --- a/api/package.json +++ b/api/package.json @@ -30,6 +30,7 @@ "class-validator": "^0.10.0", "csv": "^5.1.1", "ejs": "^2.6.1", + "express-rate-limit": "^5.1.3", "generate-password": "^1.4.1", "gettext-parser": "^3.1.0", "handlebars": "^4.5.3", From 461c2d82a02a7640734ffcd72bc547b4c73c5cae Mon Sep 17 00:00:00 2001 From: Arjun Shibu Date: Wed, 4 Nov 2020 10:10:54 +0530 Subject: [PATCH 3/5] Update user.service.ts --- api/src/services/user.service.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index 92ea3868..d49ea724 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -190,14 +190,6 @@ export class UserService { .subtract(15, 'minutes') .toDate(); - // If lockout time has passed, reset counter - if (user.lastLogin < timeThreshold) { - user.loginAttempts = 0; - // Otherwise abort request - } else if (user.loginAttempts >= 3) { - throw new TooManyRequestsException('too many login attempts'); - } - switch (grantType) { case GrantType.Password: if (!user.encryptedPassword) { From 7d05d739307a08db3c33df3f1fd98666ba972e8b Mon Sep 17 00:00:00 2001 From: Arjun Shibu Date: Wed, 4 Nov 2020 10:13:30 +0530 Subject: [PATCH 4/5] Update user.service.ts --- api/src/services/user.service.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/src/services/user.service.ts b/api/src/services/user.service.ts index d49ea724..a61bca9f 100644 --- a/api/src/services/user.service.ts +++ b/api/src/services/user.service.ts @@ -186,10 +186,6 @@ export class UserService { throw new UnauthorizedException('invalid credentials'); } - const timeThreshold = moment() - .subtract(15, 'minutes') - .toDate(); - switch (grantType) { case GrantType.Password: if (!user.encryptedPassword) { From 72ae1cd92b103bead80fcf223f79f3346d43416e Mon Sep 17 00:00:00 2001 From: Arjun Shibu Date: Wed, 4 Nov 2020 10:16:21 +0530 Subject: [PATCH 5/5] Update app.module.ts --- api/src/app.module.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/src/app.module.ts b/api/src/app.module.ts index 3fac36a8..817ca15a 100644 --- a/api/src/app.module.ts +++ b/api/src/app.module.ts @@ -5,6 +5,7 @@ import { PassportModule } from '@nestjs/passport'; import { NestExpressApplication } from '@nestjs/platform-express'; import { TypeOrmModule } from '@nestjs/typeorm'; import { renderFile } from 'ejs'; +import * as rateLimit from 'express-rate-limit'; import { config } from './config'; import { AuthController } from './controllers/auth.controller'; import { ExportsController } from './controllers/exports.controller'; @@ -100,6 +101,14 @@ export const addPipesAndFilters = (app: NestExpressApplication) => { whitelist: true, }), ); + + // rate-limiting middleware + app.use( + rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 20, // limit each IP to 20 requests per windowMs + }), + ); app.useStaticAssets(config.publicDir, { index: false, redirect: false });