diff --git a/packages/hoppscotch-backend/src/app.module.ts b/packages/hoppscotch-backend/src/app.module.ts index e181de29e..11babb2c7 100644 --- a/packages/hoppscotch-backend/src/app.module.ts +++ b/packages/hoppscotch-backend/src/app.module.ts @@ -80,7 +80,7 @@ import { loadInfraConfiguration } from './infra-config/helper'; ], }), UserModule, - AuthModule, + AuthModule.register(), AdminModule, UserSettingsModule, UserEnvironmentsModule, diff --git a/packages/hoppscotch-backend/src/auth/auth.controller.ts b/packages/hoppscotch-backend/src/auth/auth.controller.ts index 6375cb584..8aa102bbe 100644 --- a/packages/hoppscotch-backend/src/auth/auth.controller.ts +++ b/packages/hoppscotch-backend/src/auth/auth.controller.ts @@ -2,7 +2,6 @@ import { Body, Controller, Get, - InternalServerErrorException, Post, Query, Request, @@ -31,11 +30,15 @@ import { MicrosoftSSOGuard } from './guards/microsoft-sso-.guard'; import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard'; import { SkipThrottle } from '@nestjs/throttler'; import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors'; +import { ConfigService } from '@nestjs/config'; @UseGuards(ThrottlerBehindProxyGuard) @Controller({ path: 'auth', version: '1' }) export class AuthController { - constructor(private authService: AuthService) {} + constructor( + private authService: AuthService, + private configService: ConfigService, + ) {} /** ** Route to initiate magic-link auth for a users email @@ -45,8 +48,14 @@ export class AuthController { @Body() authData: SignInMagicDto, @Query('origin') origin: string, ) { - if (!authProviderCheck(AuthProvider.EMAIL)) + if ( + !authProviderCheck( + AuthProvider.EMAIL, + this.configService.get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS'), + ) + ) { throwHTTPErr({ message: AUTH_PROVIDER_NOT_SPECIFIED, statusCode: 404 }); + } const deviceIdToken = await this.authService.signInMagicLink( authData.email, diff --git a/packages/hoppscotch-backend/src/auth/auth.module.ts b/packages/hoppscotch-backend/src/auth/auth.module.ts index 2b50293d9..54b7d0898 100644 --- a/packages/hoppscotch-backend/src/auth/auth.module.ts +++ b/packages/hoppscotch-backend/src/auth/auth.module.ts @@ -13,6 +13,7 @@ import { GithubStrategy } from './strategies/github.strategy'; import { MicrosoftStrategy } from './strategies/microsoft.strategy'; import { AuthProvider, authProviderCheck } from './helper'; import { ConfigModule, ConfigService } from '@nestjs/config'; +import { loadInfraConfiguration } from 'src/infra-config/helper'; @Module({ imports: [ @@ -28,14 +29,29 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; }), }), ], - providers: [ - AuthService, - JwtStrategy, - RTJwtStrategy, - ...(authProviderCheck(AuthProvider.GOOGLE) ? [GoogleStrategy] : []), - ...(authProviderCheck(AuthProvider.GITHUB) ? [GithubStrategy] : []), - ...(authProviderCheck(AuthProvider.MICROSOFT) ? [MicrosoftStrategy] : []), - ], + providers: [AuthService, JwtStrategy, RTJwtStrategy], controllers: [AuthController], }) -export class AuthModule {} +export class AuthModule { + static async register() { + const env = await loadInfraConfiguration(); + const allowedAuthProviders = env.INFRA.VITE_ALLOWED_AUTH_PROVIDERS; + + const providers = [ + ...(authProviderCheck(AuthProvider.GOOGLE, allowedAuthProviders) + ? [GoogleStrategy] + : []), + ...(authProviderCheck(AuthProvider.GITHUB, allowedAuthProviders) + ? [GithubStrategy] + : []), + ...(authProviderCheck(AuthProvider.MICROSOFT, allowedAuthProviders) + ? [MicrosoftStrategy] + : []), + ]; + + return { + module: AuthModule, + providers, + }; + } +} diff --git a/packages/hoppscotch-backend/src/auth/guards/github-sso.guard.ts b/packages/hoppscotch-backend/src/auth/guards/github-sso.guard.ts index 1bf00bc6d..322a2d388 100644 --- a/packages/hoppscotch-backend/src/auth/guards/github-sso.guard.ts +++ b/packages/hoppscotch-backend/src/auth/guards/github-sso.guard.ts @@ -3,14 +3,25 @@ import { AuthGuard } from '@nestjs/passport'; import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper'; import { Observable } from 'rxjs'; import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class GithubSSOGuard extends AuthGuard('github') implements CanActivate { + constructor(private readonly configService: ConfigService) { + super(); + } + canActivate( context: ExecutionContext, ): boolean | Promise | Observable { - if (!authProviderCheck(AuthProvider.GITHUB)) + if ( + !authProviderCheck( + AuthProvider.GITHUB, + this.configService.get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS'), + ) + ) { throwHTTPErr({ message: AUTH_PROVIDER_NOT_SPECIFIED, statusCode: 404 }); + } return super.canActivate(context); } diff --git a/packages/hoppscotch-backend/src/auth/guards/google-sso.guard.ts b/packages/hoppscotch-backend/src/auth/guards/google-sso.guard.ts index c1f2c3b78..56dbb8a4c 100644 --- a/packages/hoppscotch-backend/src/auth/guards/google-sso.guard.ts +++ b/packages/hoppscotch-backend/src/auth/guards/google-sso.guard.ts @@ -3,14 +3,25 @@ import { AuthGuard } from '@nestjs/passport'; import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper'; import { Observable } from 'rxjs'; import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class GoogleSSOGuard extends AuthGuard('google') implements CanActivate { + constructor(private readonly configService: ConfigService) { + super(); + } + canActivate( context: ExecutionContext, ): boolean | Promise | Observable { - if (!authProviderCheck(AuthProvider.GOOGLE)) + if ( + !authProviderCheck( + AuthProvider.GOOGLE, + this.configService.get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS'), + ) + ) { throwHTTPErr({ message: AUTH_PROVIDER_NOT_SPECIFIED, statusCode: 404 }); + } return super.canActivate(context); } diff --git a/packages/hoppscotch-backend/src/auth/guards/microsoft-sso-.guard.ts b/packages/hoppscotch-backend/src/auth/guards/microsoft-sso-.guard.ts index c3a1db17b..06c6ce39e 100644 --- a/packages/hoppscotch-backend/src/auth/guards/microsoft-sso-.guard.ts +++ b/packages/hoppscotch-backend/src/auth/guards/microsoft-sso-.guard.ts @@ -3,20 +3,31 @@ import { AuthGuard } from '@nestjs/passport'; import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper'; import { Observable } from 'rxjs'; import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class MicrosoftSSOGuard extends AuthGuard('microsoft') implements CanActivate { + constructor(private readonly configService: ConfigService) { + super(); + } + canActivate( context: ExecutionContext, ): boolean | Promise | Observable { - if (!authProviderCheck(AuthProvider.MICROSOFT)) + if ( + !authProviderCheck( + AuthProvider.MICROSOFT, + this.configService.get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS'), + ) + ) { throwHTTPErr({ message: AUTH_PROVIDER_NOT_SPECIFIED, statusCode: 404, }); + } return super.canActivate(context); } diff --git a/packages/hoppscotch-backend/src/auth/helper.ts b/packages/hoppscotch-backend/src/auth/helper.ts index a0dc916ca..e0ff76fe2 100644 --- a/packages/hoppscotch-backend/src/auth/helper.ts +++ b/packages/hoppscotch-backend/src/auth/helper.ts @@ -7,6 +7,7 @@ import * as cookie from 'cookie'; import { AUTH_PROVIDER_NOT_SPECIFIED, COOKIES_NOT_FOUND } from 'src/errors'; import { throwErr } from 'src/utils'; import { ConfigService } from '@nestjs/config'; +import { loadInfraConfiguration } from 'src/infra-config/helper'; enum AuthTokenType { ACCESS_TOKEN = 'access_token', @@ -117,18 +118,18 @@ export const subscriptionContextCookieParser = (rawCookies: string) => { * @param provider Provider we want to check the presence of * @returns Boolean if provider specified is present or not */ -export function authProviderCheck(provider: string) { - const configService = new ConfigService(); - +export function authProviderCheck( + provider: string, + VITE_ALLOWED_AUTH_PROVIDERS: string, +) { if (!provider) { throwErr(AUTH_PROVIDER_NOT_SPECIFIED); } - const envVariables = configService.get('VITE_ALLOWED_AUTH_PROVIDERS') - ? configService - .get('VITE_ALLOWED_AUTH_PROVIDERS') - .split(',') - .map((provider) => provider.trim().toUpperCase()) + const envVariables = VITE_ALLOWED_AUTH_PROVIDERS + ? VITE_ALLOWED_AUTH_PROVIDERS.split(',').map((provider) => + provider.trim().toUpperCase(), + ) : []; if (!envVariables.includes(provider.toUpperCase())) return false; diff --git a/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts index 964ca401e..3f81e41e0 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/github.strategy.ts @@ -15,8 +15,8 @@ export class GithubStrategy extends PassportStrategy(Strategy) { private configService: ConfigService, ) { super({ - clientID: configService.get('GITHUB_CLIENT_ID'), - clientSecret: configService.get('GITHUB_CLIENT_SECRET'), + clientID: configService.get('INFRA.GITHUB_CLIENT_ID'), + clientSecret: configService.get('INFRA.GITHUB_CLIENT_SECRET'), callbackURL: configService.get('GITHUB_CALLBACK_URL'), scope: [configService.get('GITHUB_SCOPE')], store: true, diff --git a/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts index d50eec002..2a1b92497 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/google.strategy.ts @@ -15,8 +15,8 @@ export class GoogleStrategy extends PassportStrategy(Strategy) { private configService: ConfigService, ) { super({ - clientID: configService.get('GOOGLE_CLIENT_ID'), - clientSecret: configService.get('GOOGLE_CLIENT_SECRET'), + clientID: configService.get('INFRA.GOOGLE_CLIENT_ID'), + clientSecret: configService.get('INFRA.GOOGLE_CLIENT_SECRET'), callbackURL: configService.get('GOOGLE_CALLBACK_URL'), scope: configService.get('GOOGLE_SCOPE').split(','), passReqToCallback: true, diff --git a/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts b/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts index b495d32b1..a174e2b32 100644 --- a/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts +++ b/packages/hoppscotch-backend/src/auth/strategies/microsoft.strategy.ts @@ -15,8 +15,8 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy) { private configService: ConfigService, ) { super({ - clientID: configService.get('MICROSOFT_CLIENT_ID'), - clientSecret: configService.get('MICROSOFT_CLIENT_SECRET'), + clientID: configService.get('INFRA.MICROSOFT_CLIENT_ID'), + clientSecret: configService.get('INFRA.MICROSOFT_CLIENT_SECRET'), callbackURL: configService.get('MICROSOFT_CALLBACK_URL'), scope: [configService.get('MICROSOFT_SCOPE')], tenant: configService.get('MICROSOFT_TENANT'), diff --git a/packages/hoppscotch-backend/src/infra-config/helper.ts b/packages/hoppscotch-backend/src/infra-config/helper.ts index ff4d6be3c..ea8b12af6 100644 --- a/packages/hoppscotch-backend/src/infra-config/helper.ts +++ b/packages/hoppscotch-backend/src/infra-config/helper.ts @@ -16,7 +16,7 @@ export async function loadInfraConfiguration() { environmentObject[infraConfig.name] = infraConfig.value; }); - return environmentObject; + return { INFRA: environmentObject }; } /** @@ -24,7 +24,10 @@ export async function loadInfraConfiguration() { * (Docker will re-start the app) */ export function stopApp() { + console.log('Stopping app in 5 seconds...'); + setTimeout(() => { + console.log('Stopping app now...'); process.exit(); }, 5000); } diff --git a/packages/hoppscotch-backend/src/main.ts b/packages/hoppscotch-backend/src/main.ts index 78b6f7d95..d0afbcc77 100644 --- a/packages/hoppscotch-backend/src/main.ts +++ b/packages/hoppscotch-backend/src/main.ts @@ -16,7 +16,9 @@ async function bootstrap() { console.log(`Running in production: ${configService.get('PRODUCTION')}`); console.log(`Port: ${configService.get('PORT')}`); - checkEnvironmentAuthProvider(); + checkEnvironmentAuthProvider( + configService.get('VITE_ALLOWED_AUTH_PROVIDERS'), + ); app.use( session({ diff --git a/packages/hoppscotch-backend/src/utils.ts b/packages/hoppscotch-backend/src/utils.ts index 8a75b0dea..ef12f3eb1 100644 --- a/packages/hoppscotch-backend/src/utils.ts +++ b/packages/hoppscotch-backend/src/utils.ts @@ -162,24 +162,23 @@ export function isValidLength(title: string, length: number) { /** * This function is called by bootstrap() in main.ts - * It checks if the "VITE_ALLOWED_AUTH_PROVIDERS" environment variable is properly set or not. + * It checks if the "VITE_ALLOWED_AUTH_PROVIDERS" environment variable is properly set or not. * If not, it throws an error. */ -export function checkEnvironmentAuthProvider() { - const configService = new ConfigService(); - - if (!configService.get('VITE_ALLOWED_AUTH_PROVIDERS')) { +export function checkEnvironmentAuthProvider( + VITE_ALLOWED_AUTH_PROVIDERS: string, +) { + if (!VITE_ALLOWED_AUTH_PROVIDERS) { throw new Error(ENV_NOT_FOUND_KEY_AUTH_PROVIDERS); } - if (configService.get('VITE_ALLOWED_AUTH_PROVIDERS') === '') { + if (VITE_ALLOWED_AUTH_PROVIDERS === '') { throw new Error(ENV_EMPTY_AUTH_PROVIDERS); } - const givenAuthProviders = configService - .get('VITE_ALLOWED_AUTH_PROVIDERS') - .split(',') - .map((provider) => provider.toLocaleUpperCase()); + const givenAuthProviders = VITE_ALLOWED_AUTH_PROVIDERS.split(',').map( + (provider) => provider.toLocaleUpperCase(), + ); const supportedAuthProviders = Object.values(AuthProvider).map( (provider: string) => provider.toLocaleUpperCase(), );