diff --git a/.env.example b/.env.example index 7c4124c11..6148ee102 100644 --- a/.env.example +++ b/.env.example @@ -36,9 +36,18 @@ MICROSOFT_TENANT="common" # Mailer config MAILER_SMTP_ENABLE="true" -MAILER_SMTP_URL="smtps://user@domain.com:pass@smtp.domain.com" +MAILER_USE_ADVANCE_CONFIGS="false" MAILER_ADDRESS_FROM='"From Name Here" ' +MAILER_SMTP_URL="smtps://user@domain.com:pass@smtp.domain.com" # if MAILER_USE_ADVANCE_CONFIGS is true + +MAILER_SMTP_HOST="smtp.domain.com" # if MAILER_USE_ADVANCE_CONFIGS is false +MAILER_SMTP_PORT="587" # if MAILER_USE_ADVANCE_CONFIGS is false +MAILER_SMTP_SECURE="true" # if MAILER_USE_ADVANCE_CONFIGS is false +MAILER_SMTP_USER="user@domain.com" # if MAILER_USE_ADVANCE_CONFIGS is false +MAILER_SMTP_PASSWORD="pass" # if MAILER_USE_ADVANCE_CONFIGS is false +MAILER_TLS_REJECT_UNAUTHORIZED="true" # if MAILER_USE_ADVANCE_CONFIGS is false + # Rate Limit Config RATE_LIMIT_TTL=60 # In seconds RATE_LIMIT_MAX=100 # Max requests per IP diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index 208a80464..5c92b0304 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -678,6 +678,26 @@ export const MAILER_SMTP_URL_UNDEFINED = 'mailer/smtp_url_undefined' as const; export const MAILER_FROM_ADDRESS_UNDEFINED = 'mailer/from_address_undefined' as const; +/** + * MAILER_SMTP_USER environment variable is not defined + * (MailerModule) + */ +export const MAILER_SMTP_USER_UNDEFINED = 'mailer/smtp_user_undefined' as const; + +/** + * MAILER_SMTP_PASSWORD environment variable is not defined + * (MailerModule) + */ +export const MAILER_SMTP_PASSWORD_UNDEFINED = + 'mailer/smtp_password_undefined' as const; + +/** + * MAILER_USE_GRANULAR environment variable is not defined + * (MailerModule) + */ +export const MAILER_USE_ADVANCE_CONFIGS_INVALID_VALUE = + 'mailer/use_advance_configs_invalid_value' as const; + /** * SharedRequest invalid request JSON format * (ShortcodeService) diff --git a/packages/hoppscotch-backend/src/infra-config/helper.ts b/packages/hoppscotch-backend/src/infra-config/helper.ts index de358a947..f6d681a24 100644 --- a/packages/hoppscotch-backend/src/infra-config/helper.ts +++ b/packages/hoppscotch-backend/src/infra-config/helper.ts @@ -33,10 +33,17 @@ const AuthProviderConfigurations = { InfraConfigEnum.MICROSOFT_SCOPE, InfraConfigEnum.MICROSOFT_TENANT, ], - [AuthProvider.EMAIL]: [ - InfraConfigEnum.MAILER_SMTP_URL, - InfraConfigEnum.MAILER_ADDRESS_FROM, - ], + [AuthProvider.EMAIL]: !!process.env.MAILER_USE_ADVANCE_CONFIGS + ? [ + InfraConfigEnum.MAILER_SMTP_HOST, + InfraConfigEnum.MAILER_SMTP_PORT, + InfraConfigEnum.MAILER_SMTP_SECURE, + InfraConfigEnum.MAILER_SMTP_USER, + InfraConfigEnum.MAILER_SMTP_PASSWORD, + InfraConfigEnum.MAILER_TLS_REJECT_UNAUTHORIZED, + InfraConfigEnum.MAILER_ADDRESS_FROM, + ] + : [InfraConfigEnum.MAILER_SMTP_URL, InfraConfigEnum.MAILER_ADDRESS_FROM], }; /** @@ -79,6 +86,10 @@ export async function getDefaultInfraConfigs(): Promise< name: InfraConfigEnum.MAILER_SMTP_ENABLE, value: process.env.MAILER_SMTP_ENABLE ?? 'true', }, + { + name: InfraConfigEnum.MAILER_USE_ADVANCE_CONFIGS, + value: process.env.MAILER_USE_ADVANCE_CONFIGS ?? 'false', + }, { name: InfraConfigEnum.MAILER_SMTP_URL, value: process.env.MAILER_SMTP_URL, @@ -87,6 +98,30 @@ export async function getDefaultInfraConfigs(): Promise< name: InfraConfigEnum.MAILER_ADDRESS_FROM, value: process.env.MAILER_ADDRESS_FROM, }, + { + name: InfraConfigEnum.MAILER_SMTP_HOST, + value: process.env.MAILER_SMTP_HOST, + }, + { + name: InfraConfigEnum.MAILER_SMTP_PORT, + value: process.env.MAILER_SMTP_PORT, + }, + { + name: InfraConfigEnum.MAILER_SMTP_SECURE, + value: process.env.MAILER_SMTP_SECURE, + }, + { + name: InfraConfigEnum.MAILER_SMTP_USER, + value: process.env.MAILER_SMTP_USER, + }, + { + name: InfraConfigEnum.MAILER_SMTP_PASSWORD, + value: process.env.MAILER_SMTP_PASSWORD, + }, + { + name: InfraConfigEnum.MAILER_TLS_REJECT_UNAUTHORIZED, + value: process.env.MAILER_TLS_REJECT_UNAUTHORIZED, + }, { name: InfraConfigEnum.GOOGLE_CLIENT_ID, value: process.env.GOOGLE_CLIENT_ID, 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 4bc9cb70a..7ed744d47 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts @@ -370,6 +370,13 @@ export class InfraConfigService implements OnModuleInit { ) return E.left(INFRA_CONFIG_INVALID_INPUT); break; + case InfraConfigEnum.MAILER_USE_ADVANCE_CONFIGS: + if ( + infraConfigs[i].value !== 'true' && + infraConfigs[i].value !== 'false' + ) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; case InfraConfigEnum.MAILER_SMTP_URL: const isValidUrl = validateSMTPUrl(infraConfigs[i].value); if (!isValidUrl) return E.left(INFRA_CONFIG_INVALID_INPUT); @@ -378,6 +385,32 @@ export class InfraConfigService implements OnModuleInit { const isValidEmail = validateSMTPEmail(infraConfigs[i].value); if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT); break; + case InfraConfigEnum.MAILER_SMTP_HOST: + if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnum.MAILER_SMTP_PORT: + if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnum.MAILER_SMTP_SECURE: + if ( + infraConfigs[i].value !== 'true' && + infraConfigs[i].value !== 'false' + ) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnum.MAILER_SMTP_USER: + if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnum.MAILER_SMTP_PASSWORD: + if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); + break; + case InfraConfigEnum.MAILER_TLS_REJECT_UNAUTHORIZED: + if ( + infraConfigs[i].value !== 'true' && + infraConfigs[i].value !== 'false' + ) + return E.left(INFRA_CONFIG_INVALID_INPUT); + break; case InfraConfigEnum.GOOGLE_CLIENT_ID: if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT); break; diff --git a/packages/hoppscotch-backend/src/mailer/mailer.module.ts b/packages/hoppscotch-backend/src/mailer/mailer.module.ts index d36762517..15ee44bd4 100644 --- a/packages/hoppscotch-backend/src/mailer/mailer.module.ts +++ b/packages/hoppscotch-backend/src/mailer/mailer.module.ts @@ -5,32 +5,76 @@ import { MailerService } from './mailer.service'; import { throwErr } from 'src/utils'; import { MAILER_FROM_ADDRESS_UNDEFINED, + MAILER_SMTP_PASSWORD_UNDEFINED, MAILER_SMTP_URL_UNDEFINED, + MAILER_SMTP_USER_UNDEFINED, + MAILER_USE_ADVANCE_CONFIGS_INVALID_VALUE, } from 'src/errors'; import { ConfigService } from '@nestjs/config'; import { loadInfraConfiguration } from 'src/infra-config/helper'; import { MailerEventListener } from './mailer.listener'; +import { TransportType } from '@nestjs-modules/mailer/dist/interfaces/mailer-options.interface'; @Global() @Module({}) export class MailerModule { static async register() { + const config = new ConfigService(); const env = await loadInfraConfiguration(); - // If mailer SMTP is DISABLED, return the module without any configuration + // If mailer SMTP is DISABLED, return the module without any configuration (service, listener, etc.) if (env.INFRA.MAILER_SMTP_ENABLE !== 'true') { console.log('Mailer SMTP is disabled'); return { module: MailerModule }; } - // If mailer is ENABLED, return the module with configuration - let mailerSmtpUrl = env.INFRA.MAILER_SMTP_URL; - let mailerAddressFrom = env.INFRA.MAILER_ADDRESS_FROM; + // If mailer is ENABLED, return the module with configuration (service, listener, etc.) + let transportOption: TransportType; - if (!env.INFRA.MAILER_SMTP_URL || !env.INFRA.MAILER_ADDRESS_FROM) { - const config = new ConfigService(); - mailerSmtpUrl = config.get('MAILER_SMTP_URL'); - mailerAddressFrom = config.get('MAILER_ADDRESS_FROM'); + const mailerAddressFrom = + env.INFRA.MAILER_ADDRESS_FROM ?? + config.get('MAILER_ADDRESS_FROM') ?? + throwErr(MAILER_SMTP_URL_UNDEFINED); + + if ( + (env.INFRA.MAILER_USE_ADVANCE_CONFIGS ?? + config.get('MAILER_USE_ADVANCE_CONFIGS')) === 'false' + ) { + console.log('Using simple mailer configuration'); + + transportOption = + env.INFRA.MAILER_SMTP_URL ?? + config.get('MAILER_SMTP_URL') ?? + throwErr(MAILER_SMTP_URL_UNDEFINED); + } else if ( + (env.INFRA.MAILER_USE_ADVANCE_CONFIGS ?? + config.get('MAILER_USE_ADVANCE_CONFIGS')) === 'true' + ) { + console.log('Using advance mailer configuration'); + + transportOption = { + host: env.INFRA.MAILER_SMTP_HOST ?? config.get('MAILER_SMTP_HOST'), + port: +env.INFRA.MAILER_SMTP_PORT ?? +config.get('MAILER_SMTP_PORT'), + secure: + !!env.INFRA.MAILER_SMTP_SECURE ?? !!config.get('MAILER_SMTP_SECURE'), + auth: { + user: + env.INFRA.MAILER_SMTP_USER ?? + config.get('MAILER_SMTP_USER') ?? + throwErr(MAILER_SMTP_USER_UNDEFINED), + pass: + env.INFRA.MAILER_SMTP_PASSWORD ?? + config.get('MAILER_SMTP_PASSWORD') ?? + throwErr(MAILER_SMTP_PASSWORD_UNDEFINED), + }, + tls: { + rejectUnauthorized: + !!env.INFRA.MAILER_TLS_REJECT_UNAUTHORIZED ?? + !!config.get('MAILER_TLS_REJECT_UNAUTHORIZED'), + }, + }; + } else { + throwErr(MAILER_USE_ADVANCE_CONFIGS_INVALID_VALUE); } return { @@ -38,9 +82,9 @@ export class MailerModule { providers: [MailerService, MailerEventListener], imports: [ NestMailerModule.forRoot({ - transport: mailerSmtpUrl ?? throwErr(MAILER_SMTP_URL_UNDEFINED), + transport: transportOption, defaults: { - from: mailerAddressFrom ?? throwErr(MAILER_FROM_ADDRESS_UNDEFINED), + from: mailerAddressFrom, }, template: { dir: __dirname + '/templates', diff --git a/packages/hoppscotch-backend/src/types/InfraConfig.ts b/packages/hoppscotch-backend/src/types/InfraConfig.ts index 82354b91f..79e7113bc 100644 --- a/packages/hoppscotch-backend/src/types/InfraConfig.ts +++ b/packages/hoppscotch-backend/src/types/InfraConfig.ts @@ -1,8 +1,16 @@ export enum InfraConfigEnum { MAILER_SMTP_ENABLE = 'MAILER_SMTP_ENABLE', + MAILER_USE_ADVANCE_CONFIGS = 'MAILER_USE_ADVANCE_CONFIGS', MAILER_SMTP_URL = 'MAILER_SMTP_URL', MAILER_ADDRESS_FROM = 'MAILER_ADDRESS_FROM', + MAILER_SMTP_HOST = 'MAILER_SMTP_HOST', + MAILER_SMTP_PORT = 'MAILER_SMTP_PORT', + MAILER_SMTP_SECURE = 'MAILER_SMTP_SECURE', + MAILER_SMTP_USER = 'MAILER_SMTP_USER', + MAILER_SMTP_PASSWORD = 'MAILER_SMTP_PASSWORD', + MAILER_TLS_REJECT_UNAUTHORIZED = 'MAILER_TLS_REJECT_UNAUTHORIZED', + GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID', GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET', GOOGLE_CALLBACK_URL = 'GOOGLE_CALLBACK_URL',