diff --git a/packages/hoppscotch-backend/src/admin/infra.resolver.ts b/packages/hoppscotch-backend/src/admin/infra.resolver.ts index 0666827fc..1c08e9a2f 100644 --- a/packages/hoppscotch-backend/src/admin/infra.resolver.ts +++ b/packages/hoppscotch-backend/src/admin/infra.resolver.ts @@ -32,7 +32,7 @@ import { EnableAndDisableSSOArgs, InfraConfigArgs, } from 'src/infra-config/input-args'; -import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; +import { InfraConfigEnum } from 'src/types/InfraConfig'; import { ServiceStatus } from 'src/infra-config/helper'; @UseGuards(GqlThrottlerGuard) @@ -274,10 +274,10 @@ export class InfraResolver { async infraConfigs( @Args({ name: 'configNames', - type: () => [InfraConfigEnumForClient], + type: () => [InfraConfigEnum], description: 'Configs to fetch', }) - names: InfraConfigEnumForClient[], + names: InfraConfigEnum[], ) { const infraConfigs = await this.infraConfigService.getMany(names); if (E.isLeft(infraConfigs)) throwErr(infraConfigs.left); diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index ef7fbc0df..68a579485 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -731,6 +731,13 @@ export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const; export const INFRA_CONFIG_SERVICE_NOT_CONFIGURED = 'infra_config/service_not_configured' as const; +/** + * Infra Config update/fetch operation not allowed + * (InfraConfigService) + */ +export const INFRA_CONFIG_OPERATION_NOT_ALLOWED = + 'infra_config/operation_not_allowed'; + /** * Error message for when the database table does not exist * (InfraConfigService) diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.controller.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.controller.ts index 92468fe3f..e0b11d78f 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.controller.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.controller.ts @@ -5,7 +5,7 @@ import * as E from 'fp-ts/Either'; import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; import { RESTAdminGuard } from 'src/admin/guards/rest-admin.guard'; import { RESTError } from 'src/types/RESTError'; -import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; +import { InfraConfigEnum } from 'src/types/InfraConfig'; import { throwHTTPErr } from 'src/utils'; @UseGuards(ThrottlerBehindProxyGuard) @@ -17,7 +17,7 @@ export class SiteController { @UseGuards(JwtAuthGuard, RESTAdminGuard) async fetchSetupInfo() { const status = await this.infraConfigService.get( - InfraConfigEnumForClient.IS_FIRST_TIME_INFRA_SETUP, + InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP, ); if (E.isLeft(status)) @@ -32,7 +32,7 @@ export class SiteController { @UseGuards(JwtAuthGuard, RESTAdminGuard) async setSetupAsComplete() { const res = await this.infraConfigService.update( - InfraConfigEnumForClient.IS_FIRST_TIME_INFRA_SETUP, + InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP, false.toString(), false, ); diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts index 6335261ca..7962c6965 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts @@ -1,6 +1,6 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { AuthProvider } from 'src/auth/helper'; -import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; +import { InfraConfigEnum } from 'src/types/InfraConfig'; import { ServiceStatus } from './helper'; @ObjectType() @@ -8,7 +8,7 @@ export class InfraConfig { @Field({ description: 'Infra Config Name', }) - name: InfraConfigEnumForClient; + name: InfraConfigEnum; @Field({ description: 'Infra Config Value', @@ -16,7 +16,7 @@ export class InfraConfig { value: string; } -registerEnumType(InfraConfigEnumForClient, { +registerEnumType(InfraConfigEnum, { name: 'InfraConfigEnum', }); 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 e3e379c8a..a024d9f33 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts @@ -3,19 +3,16 @@ import { InfraConfig } from './infra-config.model'; import { PrismaService } from 'src/prisma/prisma.service'; import { InfraConfig as DBInfraConfig } from '@prisma/client'; import * as E from 'fp-ts/Either'; -import { - InfraConfigEnum, - InfraConfigEnumForClient, -} from 'src/types/InfraConfig'; +import { InfraConfigEnum } from 'src/types/InfraConfig'; import { AUTH_PROVIDER_NOT_SPECIFIED, DATABASE_TABLE_NOT_EXIST, INFRA_CONFIG_INVALID_INPUT, INFRA_CONFIG_NOT_FOUND, - INFRA_CONFIG_NOT_LISTED, INFRA_CONFIG_RESET_FAILED, INFRA_CONFIG_UPDATE_FAILED, INFRA_CONFIG_SERVICE_NOT_CONFIGURED, + INFRA_CONFIG_OPERATION_NOT_ALLOWED, } from 'src/errors'; import { throwErr, @@ -24,13 +21,7 @@ import { validateUrl, } from 'src/utils'; import { ConfigService } from '@nestjs/config'; -import { - ServiceStatus, - getDefaultInfraConfigs, - stopApp, - generateAnalyticsUserId, - getConfiguredSSOProviders, -} from './helper'; +import { ServiceStatus, getDefaultInfraConfigs, stopApp } from './helper'; import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args'; import { AuthProvider } from 'src/auth/helper'; @@ -41,6 +32,20 @@ export class InfraConfigService implements OnModuleInit { private readonly configService: ConfigService, ) {} + // Following fields are not updatable by `infraConfigs` Mutation. Use dedicated mutations for these fields instead. + EXCLUDE_FROM_UPDATE_CONFIGS = [ + InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS, + InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION, + InfraConfigEnum.ANALYTICS_USER_ID, + InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP, + ]; + // Following fields can not be fetched by `infraConfigs` Query. Use dedicated queries for these fields instead. + EXCLUDE_FROM_FETCH_CONFIGS = [ + InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS, + InfraConfigEnum.ANALYTICS_USER_ID, + InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP, + ]; + async onModuleInit() { await this.initializeInfraConfigTable(); } @@ -109,11 +114,7 @@ export class InfraConfigService implements OnModuleInit { * @param restartEnabled If true, restart the app after updating the InfraConfig * @returns InfraConfig model */ - async update( - name: InfraConfigEnumForClient | InfraConfigEnum, - value: string, - restartEnabled = false, - ) { + async update(name: InfraConfigEnum, value: string, restartEnabled = false) { const isValidate = this.validateEnvValues([{ name, value }]); if (E.isLeft(isValidate)) return E.left(isValidate.left); @@ -137,6 +138,11 @@ export class InfraConfigService implements OnModuleInit { * @returns InfraConfig model */ async updateMany(infraConfigs: InfraConfigArgs[]) { + for (let i = 0; i < infraConfigs.length; i++) { + if (this.EXCLUDE_FROM_UPDATE_CONFIGS.includes(infraConfigs[i].name)) + return E.left(INFRA_CONFIG_OPERATION_NOT_ALLOWED); + } + const isValidate = this.validateEnvValues(infraConfigs); if (E.isLeft(isValidate)) return E.left(isValidate.left); @@ -264,7 +270,7 @@ export class InfraConfigService implements OnModuleInit { * @param name Name of the InfraConfig * @returns InfraConfig model */ - async get(name: InfraConfigEnumForClient) { + async get(name: InfraConfigEnum) { try { const infraConfig = await this.prisma.infraConfig.findUniqueOrThrow({ where: { name }, @@ -281,7 +287,15 @@ export class InfraConfigService implements OnModuleInit { * @param names Names of the InfraConfigs * @returns InfraConfig model */ - async getMany(names: InfraConfigEnumForClient[]) { + async getMany(names: InfraConfigEnum[], checkDisallowedKeys: boolean = true) { + if (checkDisallowedKeys) { + // Check if the names are allowed to fetch by client + for (let i = 0; i < names.length; i++) { + if (this.EXCLUDE_FROM_FETCH_CONFIGS.includes(names[i])) + return E.left(INFRA_CONFIG_OPERATION_NOT_ALLOWED); + } + } + try { const infraConfigs = await this.prisma.infraConfig.findMany({ where: { name: { in: names } }, @@ -341,60 +355,60 @@ export class InfraConfigService implements OnModuleInit { */ validateEnvValues( infraConfigs: { - name: InfraConfigEnumForClient | InfraConfigEnum; + name: InfraConfigEnum; value: string; }[], ) { for (let i = 0; i < infraConfigs.length; i++) { switch (infraConfigs[i].name) { - case InfraConfigEnumForClient.MAILER_SMTP_URL: + case InfraConfigEnum.MAILER_SMTP_URL: const isValidUrl = validateSMTPUrl(infraConfigs[i].value); if (!isValidUrl) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MAILER_ADDRESS_FROM: + case InfraConfigEnum.MAILER_ADDRESS_FROM: const isValidEmail = validateSMTPEmail(infraConfigs[i].value); if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GOOGLE_CLIENT_ID: + case InfraConfigEnum.GOOGLE_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GOOGLE_CLIENT_SECRET: + case InfraConfigEnum.GOOGLE_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GOOGLE_CALLBACK_URL: + case InfraConfigEnum.GOOGLE_CALLBACK_URL: if (!validateUrl(infraConfigs[i].value)) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GOOGLE_SCOPE: + case InfraConfigEnum.GOOGLE_SCOPE: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GITHUB_CLIENT_ID: + case InfraConfigEnum.GITHUB_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GITHUB_CLIENT_SECRET: + case InfraConfigEnum.GITHUB_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GITHUB_CALLBACK_URL: + case InfraConfigEnum.GITHUB_CALLBACK_URL: if (!validateUrl(infraConfigs[i].value)) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.GITHUB_SCOPE: + case InfraConfigEnum.GITHUB_SCOPE: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MICROSOFT_CLIENT_ID: + case InfraConfigEnum.MICROSOFT_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MICROSOFT_CLIENT_SECRET: + case InfraConfigEnum.MICROSOFT_CLIENT_SECRET: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MICROSOFT_CALLBACK_URL: + case InfraConfigEnum.MICROSOFT_CALLBACK_URL: if (!validateUrl(infraConfigs[i].value)) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MICROSOFT_SCOPE: + case InfraConfigEnum.MICROSOFT_SCOPE: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; - case InfraConfigEnumForClient.MICROSOFT_TENANT: + case InfraConfigEnum.MICROSOFT_TENANT: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; default: diff --git a/packages/hoppscotch-backend/src/infra-config/input-args.ts b/packages/hoppscotch-backend/src/infra-config/input-args.ts index 6b4c26850..fd248e526 100644 --- a/packages/hoppscotch-backend/src/infra-config/input-args.ts +++ b/packages/hoppscotch-backend/src/infra-config/input-args.ts @@ -1,14 +1,14 @@ import { Field, InputType } from '@nestjs/graphql'; -import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; +import { InfraConfigEnum } from 'src/types/InfraConfig'; import { ServiceStatus } from './helper'; import { AuthProvider } from 'src/auth/helper'; @InputType() export class InfraConfigArgs { - @Field(() => InfraConfigEnumForClient, { + @Field(() => InfraConfigEnum, { description: 'Infra Config Name', }) - name: InfraConfigEnumForClient; + name: InfraConfigEnum; @Field({ description: 'Infra Config Value', diff --git a/packages/hoppscotch-backend/src/types/InfraConfig.ts b/packages/hoppscotch-backend/src/types/InfraConfig.ts index 74cee34af..8c02929bc 100644 --- a/packages/hoppscotch-backend/src/types/InfraConfig.ts +++ b/packages/hoppscotch-backend/src/types/InfraConfig.ts @@ -24,27 +24,3 @@ export enum InfraConfigEnum { ANALYTICS_USER_ID = 'ANALYTICS_USER_ID', IS_FIRST_TIME_INFRA_SETUP = 'IS_FIRST_TIME_INFRA_SETUP', } - -export enum InfraConfigEnumForClient { - MAILER_SMTP_URL = 'MAILER_SMTP_URL', - MAILER_ADDRESS_FROM = 'MAILER_ADDRESS_FROM', - - 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', - MICROSOFT_TENANT = 'MICROSOFT_TENANT', - - ALLOW_ANALYTICS_COLLECTION = 'ALLOW_ANALYTICS_COLLECTION', - IS_FIRST_TIME_INFRA_SETUP = 'IS_FIRST_TIME_INFRA_SETUP', -}