From 9c00d6238ec699ef1b5fb5b8fe465140759e9b2f Mon Sep 17 00:00:00 2001 From: Mir Arif Hasan Date: Thu, 4 Jan 2024 16:24:19 +0600 Subject: [PATCH] feat: sso callback url and scope added in infra-config --- .../src/infra-config/helper.ts | 6 ++ .../src/infra-config/infra-config.service.ts | 75 ++++++++++++++++++- .../src/types/InfraConfig.ts | 12 +++ packages/hoppscotch-backend/src/utils.ts | 26 +++++++ 4 files changed, 115 insertions(+), 4 deletions(-) diff --git a/packages/hoppscotch-backend/src/infra-config/helper.ts b/packages/hoppscotch-backend/src/infra-config/helper.ts index b8d66284e..92c7fa8f0 100644 --- a/packages/hoppscotch-backend/src/infra-config/helper.ts +++ b/packages/hoppscotch-backend/src/infra-config/helper.ts @@ -14,14 +14,20 @@ const AuthProviderConfigurations = { [AuthProvider.GOOGLE]: [ InfraConfigEnum.GOOGLE_CLIENT_ID, InfraConfigEnum.GOOGLE_CLIENT_SECRET, + InfraConfigEnum.GOOGLE_CALLBACK_URL, + InfraConfigEnum.GOOGLE_SCOPE, ], [AuthProvider.GITHUB]: [ InfraConfigEnum.GITHUB_CLIENT_ID, InfraConfigEnum.GITHUB_CLIENT_SECRET, + InfraConfigEnum.GITHUB_CALLBACK_URL, + InfraConfigEnum.GITHUB_SCOPE, ], [AuthProvider.MICROSOFT]: [ InfraConfigEnum.MICROSOFT_CLIENT_ID, InfraConfigEnum.MICROSOFT_CLIENT_SECRET, + InfraConfigEnum.MICROSOFT_CALLBACK_URL, + InfraConfigEnum.MICROSOFT_SCOPE, ], [AuthProvider.EMAIL]: [ InfraConfigEnum.MAILER_SMTP_URL, diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts index e0b4ab59b..9ee87b738 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts @@ -17,7 +17,13 @@ import { INFRA_CONFIG_UPDATE_FAILED, INFRA_CONFIG_SERVICE_NOT_CONFIGURED, } from 'src/errors'; -import { throwErr, validateSMTPEmail, validateSMTPUrl } from 'src/utils'; +import { + throwErr, + validateSMTPEmail, + validateSMTPUrl, + validateSSOScope, + validateUrl, +} from 'src/utils'; import { ConfigService } from '@nestjs/config'; import { ServiceStatus, @@ -60,6 +66,14 @@ export class InfraConfigService implements OnModuleInit { name: InfraConfigEnum.GOOGLE_CLIENT_SECRET, value: process.env.GOOGLE_CLIENT_SECRET, }, + { + name: InfraConfigEnum.GOOGLE_CALLBACK_URL, + value: process.env.GOOGLE_CALLBACK_URL, + }, + { + name: InfraConfigEnum.GOOGLE_SCOPE, + value: process.env.GOOGLE_SCOPE, + }, { name: InfraConfigEnum.GITHUB_CLIENT_ID, value: process.env.GITHUB_CLIENT_ID, @@ -68,6 +82,14 @@ export class InfraConfigService implements OnModuleInit { name: InfraConfigEnum.GITHUB_CLIENT_SECRET, value: process.env.GITHUB_CLIENT_SECRET, }, + { + name: InfraConfigEnum.GITHUB_CALLBACK_URL, + value: process.env.GITHUB_CALLBACK_URL, + }, + { + name: InfraConfigEnum.GITHUB_SCOPE, + value: process.env.GITHUB_SCOPE, + }, { name: InfraConfigEnum.MICROSOFT_CLIENT_ID, value: process.env.MICROSOFT_CLIENT_ID, @@ -76,6 +98,14 @@ export class InfraConfigService implements OnModuleInit { name: InfraConfigEnum.MICROSOFT_CLIENT_SECRET, value: process.env.MICROSOFT_CLIENT_SECRET, }, + { + name: InfraConfigEnum.MICROSOFT_CALLBACK_URL, + value: process.env.MICROSOFT_CALLBACK_URL, + }, + { + name: InfraConfigEnum.MICROSOFT_SCOPE, + value: process.env.MICROSOFT_SCOPE, + }, { name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS, value: getConfiguredSSOProviders(), @@ -230,12 +260,25 @@ export class InfraConfigService implements OnModuleInit { ) { switch (service) { case AuthProvider.GOOGLE: - return configMap.GOOGLE_CLIENT_ID && configMap.GOOGLE_CLIENT_SECRET; + return ( + configMap.GOOGLE_CLIENT_ID && + configMap.GOOGLE_CLIENT_SECRET && + configMap.GOOGLE_CALLBACK_URL && + configMap.GOOGLE_SCOPE + ); case AuthProvider.GITHUB: - return configMap.GITHUB_CLIENT_ID && configMap.GITHUB_CLIENT_SECRET; + return ( + configMap.GITHUB_CLIENT_ID && + configMap.GITHUB_CLIENT_SECRET && + configMap.GITHUB_CALLBACK_URL && + configMap.GITHUB_SCOPE + ); case AuthProvider.MICROSOFT: return ( - configMap.MICROSOFT_CLIENT_ID && configMap.MICROSOFT_CLIENT_SECRET + configMap.MICROSOFT_CLIENT_ID && + configMap.MICROSOFT_CLIENT_SECRET && + configMap.MICROSOFT_CALLBACK_URL && + configMap.MICROSOFT_SCOPE ); case AuthProvider.EMAIL: return configMap.MAILER_SMTP_URL && configMap.MAILER_ADDRESS_FROM; @@ -407,18 +450,42 @@ export class InfraConfigService implements OnModuleInit { case InfraConfigEnumForClient.GOOGLE_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; + case InfraConfigEnumForClient.GOOGLE_CALLBACK_URL: + if (!validateUrl(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnumForClient.GOOGLE_SCOPE: + if (!validateSSOScope(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; case InfraConfigEnumForClient.GITHUB_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; case InfraConfigEnumForClient.GITHUB_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; + case InfraConfigEnumForClient.GITHUB_CALLBACK_URL: + if (!validateUrl(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnumForClient.GITHUB_SCOPE: + if (!validateSSOScope(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; case InfraConfigEnumForClient.MICROSOFT_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; case InfraConfigEnumForClient.MICROSOFT_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; + case InfraConfigEnumForClient.MICROSOFT_CALLBACK_URL: + if (!validateUrl(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnumForClient.MICROSOFT_SCOPE: + if (!validateSSOScope(infraConfigs[i].value)) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; default: break; } diff --git a/packages/hoppscotch-backend/src/types/InfraConfig.ts b/packages/hoppscotch-backend/src/types/InfraConfig.ts index 3836194e5..02ccb41ea 100644 --- a/packages/hoppscotch-backend/src/types/InfraConfig.ts +++ b/packages/hoppscotch-backend/src/types/InfraConfig.ts @@ -4,12 +4,18 @@ export enum InfraConfigEnum { GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID', GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET', + GOOGLE_CALLBACK_URL = 'GOOGLE_CALLBACK_URL', + GOOGLE_SCOPE = 'GOOGLE_SCOPE', GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID', GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET', + GITHUB_CALLBACK_URL = 'GITHUB_CALLBACK_URL', + GITHUB_SCOPE = 'GITHUB_SCOPE', MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID', MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET', + MICROSOFT_CALLBACK_URL = 'MICROSOFT_CALLBACK_URL', + MICROSOFT_SCOPE = 'MICROSOFT_SCOPE', VITE_ALLOWED_AUTH_PROVIDERS = 'VITE_ALLOWED_AUTH_PROVIDERS', @@ -24,12 +30,18 @@ export enum InfraConfigEnumForClient { GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID', GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET', + GOOGLE_CALLBACK_URL = 'GOOGLE_CALLBACK_URL', + GOOGLE_SCOPE = 'GOOGLE_SCOPE', GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID', GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET', + GITHUB_CALLBACK_URL = 'GITHUB_CALLBACK_URL', + GITHUB_SCOPE = 'GITHUB_SCOPE', MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID', MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET', + MICROSOFT_CALLBACK_URL = 'MICROSOFT_CALLBACK_URL', + MICROSOFT_SCOPE = 'MICROSOFT_SCOPE', ALLOW_ANALYTICS_COLLECTION = 'ALLOW_ANALYTICS_COLLECTION', IS_FIRST_TIME_INFRA_SETUP = 'IS_FIRST_TIME_INFRA_SETUP', diff --git a/packages/hoppscotch-backend/src/utils.ts b/packages/hoppscotch-backend/src/utils.ts index 043bd46f9..d91653d81 100644 --- a/packages/hoppscotch-backend/src/utils.ts +++ b/packages/hoppscotch-backend/src/utils.ts @@ -183,6 +183,32 @@ export const validateSMTPUrl = (url: string) => { return false; }; +/** + * Checks to see if the URL is valid or not + * @param url The URL to validate + * @returns boolean + */ +export const validateUrl = (url: string) => { + const urlRegex = /^(https?|ftp):\/\/(-\.)?([^\s\/?\.#-]+\.?)+(\/[^\s]*)?$/i; + return urlRegex.test(url); +}; + +/** + * Validate SSO (Google, Github, Microsoft) Scope + * @param scope The scope to validate + * @returns boolean + */ +export const validateSSOScope = (scope: string) => { + if (!scope || scope.length === 0) return false; + + const scopes = scope.split(','); + scopes.forEach((aScope) => { + if (aScope.length === 0) return false; + }); + + return true; +}; + /** * String to JSON parser * @param {str} str The string to parse