From 09af75b0efcada110979a2705822175266f3156e Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:02:17 +0530 Subject: [PATCH 1/4] feat : added cors and helmet for security --- package.json | 4 +++- src/main.ts | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8eef533..51aff65 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "middleware_micorservice", + "name": "middleware_microservice", "version": "0.0.1", "description": "", "author": "", @@ -34,7 +34,9 @@ "cache-manager-memory-store": "^1.1.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", + "cors": "^2.8.5", "dotenv": "^16.4.5", + "helmet": "^8.0.0", "nest-winston": "^1.9.6", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.14", diff --git a/src/main.ts b/src/main.ts index 2717bc9..1d4b816 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,33 @@ import { NestFactory } from '@nestjs/core'; +import helmet from 'helmet'; import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import * as dotenv from 'dotenv'; +import { ConfigService } from '@nestjs/config'; +import { InternalServerErrorException } from '@nestjs/common'; async function bootstrap() { dotenv.config(); // Load environment variables from .env file - const app = await NestFactory.create(AppModule); + const app = await NestFactory.create(AppModule, { cors: true }); + + const configService = app.get(ConfigService); + + const corsOriginList = configService + .get('CORS_ORIGIN_LIST') + ?.split(','); + + console.log(corsOriginList, 'sda'); + + if (corsOriginList[0] !== '*' && !validateCorsOriginList(corsOriginList)) { + throw new Error('Invalid CORS_ORIGIN_LIST'); + } + + const corsOptions = { + origin: corsOriginList, // Array of allowed origins + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // Specify allowed methods + credentials: true, // Allow credentials (cookies, authorization headers) + }; + const config = new DocumentBuilder() .setTitle('Middleware APIs') .setDescription('The Middlware service') @@ -17,8 +39,35 @@ async function bootstrap() { .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api/swagger-docs', app, document); + + app.use((req, res, next) => { + const origin = req.headers.origin; + + if (corsOriginList.includes(origin) || corsOriginList[0] === '*') { + res.setHeader('Access-Control-Allow-Origin', origin); + } else { + throw new InternalServerErrorException('Invalid CORS_ORIGIN'); + } + res.setHeader('Access-Control-Allow-Credentials', 'true'); + res.header( + 'Access-Control-Allow-Methods', + 'GET,HEAD,PUT,PATCH,POST,DELETE', + ); + next(); + }); + + app.enableCors(corsOptions); + app.use(helmet()); + await app.listen(4000, () => { console.log(`Server middleware on port - 4000`); }); } + +function validateCorsOriginList(corsOriginList: string[]): boolean { + return corsOriginList.every((origin) => { + return origin.includes('http://') || origin.includes('https://'); + }); +} + bootstrap(); From fb4859c51ce9a98626dcaa7834c283812d2828ea Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:06:34 +0530 Subject: [PATCH 2/4] chore : removed console log --- src/main.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index 1d4b816..ae6e99a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,8 +16,6 @@ async function bootstrap() { .get('CORS_ORIGIN_LIST') ?.split(','); - console.log(corsOriginList, 'sda'); - if (corsOriginList[0] !== '*' && !validateCorsOriginList(corsOriginList)) { throw new Error('Invalid CORS_ORIGIN_LIST'); } From 9ee37bc7d0de3a4092a9d6d38756c17b66bf9899 Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:21:31 +0530 Subject: [PATCH 3/4] chore : solved code rabbit --- src/main.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index ae6e99a..8944f81 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,11 +4,11 @@ import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import * as dotenv from 'dotenv'; import { ConfigService } from '@nestjs/config'; -import { InternalServerErrorException } from '@nestjs/common'; +import { ForbiddenException } from '@nestjs/common'; async function bootstrap() { dotenv.config(); // Load environment variables from .env file - const app = await NestFactory.create(AppModule, { cors: true }); + const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); @@ -16,6 +16,10 @@ async function bootstrap() { .get('CORS_ORIGIN_LIST') ?.split(','); + if (!corsOriginList || corsOriginList.length === 0) { + throw new Error('CORS_ORIGIN_LIST is not defined or empty'); + } + if (corsOriginList[0] !== '*' && !validateCorsOriginList(corsOriginList)) { throw new Error('Invalid CORS_ORIGIN_LIST'); } @@ -44,7 +48,7 @@ async function bootstrap() { if (corsOriginList.includes(origin) || corsOriginList[0] === '*') { res.setHeader('Access-Control-Allow-Origin', origin); } else { - throw new InternalServerErrorException('Invalid CORS_ORIGIN'); + throw new ForbiddenException('Origin not allowed'); } res.setHeader('Access-Control-Allow-Credentials', 'true'); res.header( @@ -64,7 +68,12 @@ async function bootstrap() { function validateCorsOriginList(corsOriginList: string[]): boolean { return corsOriginList.every((origin) => { - return origin.includes('http://') || origin.includes('https://'); + try { + new URL(origin); + return true; + } catch (error) { + return false; + } }); } From ea3167044d173c8abe2340bd8c9a8a4ede152514 Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:41:03 +0530 Subject: [PATCH 4/4] chore : code rabbit suggestions --- src/main.ts | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8944f81..f7edd33 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,14 +25,20 @@ async function bootstrap() { } const corsOptions = { - origin: corsOriginList, // Array of allowed origins + origin: (origin, callback) => { + if (corsOriginList.includes(origin) || corsOriginList[0] === '*') { + callback(null, true); + } else { + callback(new ForbiddenException('Origin not allowed')); + } + }, methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', // Specify allowed methods credentials: true, // Allow credentials (cookies, authorization headers) }; const config = new DocumentBuilder() .setTitle('Middleware APIs') - .setDescription('The Middlware service') + .setDescription('The Middleware service') .setVersion('1.0') .addApiKey( { type: 'apiKey', name: 'Authorization', in: 'header' }, @@ -42,22 +48,6 @@ async function bootstrap() { const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api/swagger-docs', app, document); - app.use((req, res, next) => { - const origin = req.headers.origin; - - if (corsOriginList.includes(origin) || corsOriginList[0] === '*') { - res.setHeader('Access-Control-Allow-Origin', origin); - } else { - throw new ForbiddenException('Origin not allowed'); - } - res.setHeader('Access-Control-Allow-Credentials', 'true'); - res.header( - 'Access-Control-Allow-Methods', - 'GET,HEAD,PUT,PATCH,POST,DELETE', - ); - next(); - }); - app.enableCors(corsOptions); app.use(helmet());