chore: smtp url validation added
This commit is contained in:
@@ -670,6 +670,12 @@ export const INFRA_CONFIG_NOT_LISTED =
|
|||||||
*/
|
*/
|
||||||
export const INFRA_CONFIG_RESET_FAILED = 'infra_config/reset_failed' as const;
|
export const INFRA_CONFIG_RESET_FAILED = 'infra_config/reset_failed' as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infra Config reset failed
|
||||||
|
* (InfraConfigService)
|
||||||
|
*/
|
||||||
|
export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error message for when the database table does not exist
|
* Error message for when the database table does not exist
|
||||||
* (InfraConfigService)
|
* (InfraConfigService)
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {
|
|||||||
} from 'src/types/InfraConfig';
|
} from 'src/types/InfraConfig';
|
||||||
import {
|
import {
|
||||||
DATABASE_TABLE_NOT_EXIST,
|
DATABASE_TABLE_NOT_EXIST,
|
||||||
|
INFRA_CONFIG_INVALID_INPUT,
|
||||||
INFRA_CONFIG_NOT_FOUND,
|
INFRA_CONFIG_NOT_FOUND,
|
||||||
INFRA_CONFIG_NOT_LISTED,
|
INFRA_CONFIG_NOT_LISTED,
|
||||||
INFRA_CONFIG_RESET_FAILED,
|
INFRA_CONFIG_RESET_FAILED,
|
||||||
INFRA_CONFIG_UPDATE_FAILED,
|
INFRA_CONFIG_UPDATE_FAILED,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import { throwErr } from 'src/utils';
|
import { throwErr, validateUrl } from 'src/utils';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { AuthProviderStatus, stopApp } from './helper';
|
import { AuthProviderStatus, stopApp } from './helper';
|
||||||
import { InfraConfigArgs } from './input-args';
|
import { InfraConfigArgs } from './input-args';
|
||||||
@@ -130,7 +131,13 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* @param value Value of the InfraConfig
|
* @param value Value of the InfraConfig
|
||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async update(name: InfraConfigEnum, value: string) {
|
async update(
|
||||||
|
name: InfraConfigEnumForClient | InfraConfigEnum,
|
||||||
|
value: string,
|
||||||
|
) {
|
||||||
|
const isValidate = this.validateEnvValues([{ name, value }]);
|
||||||
|
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const infraConfig = await this.prisma.infraConfig.update({
|
const infraConfig = await this.prisma.infraConfig.update({
|
||||||
where: { name },
|
where: { name },
|
||||||
@@ -151,6 +158,9 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async updateMany(infraConfigs: InfraConfigArgs[]) {
|
async updateMany(infraConfigs: InfraConfigArgs[]) {
|
||||||
|
const isValidate = this.validateEnvValues(infraConfigs);
|
||||||
|
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.prisma.$transaction(async (tx) => {
|
await this.prisma.$transaction(async (tx) => {
|
||||||
const deleteCount = await tx.infraConfig.deleteMany({
|
const deleteCount = await tx.infraConfig.deleteMany({
|
||||||
@@ -165,7 +175,7 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (deleteCount.count !== createCount.count) {
|
if (deleteCount.count !== createCount.count) {
|
||||||
throwErr(INFRA_CONFIG_UPDATE_FAILED);
|
return E.left(INFRA_CONFIG_UPDATE_FAILED);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -205,7 +215,7 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
||||||
newEnabledAuthProviders.join(','),
|
newEnabledAuthProviders.join(','),
|
||||||
);
|
);
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
||||||
|
|
||||||
return E.right(true);
|
return E.right(true);
|
||||||
}
|
}
|
||||||
@@ -275,4 +285,20 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
return E.left(INFRA_CONFIG_RESET_FAILED);
|
return E.left(INFRA_CONFIG_RESET_FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateEnvValues(
|
||||||
|
infraConfigs: {
|
||||||
|
name: InfraConfigEnumForClient | InfraConfigEnum;
|
||||||
|
value: string;
|
||||||
|
}[],
|
||||||
|
) {
|
||||||
|
for (let i = 0; i < infraConfigs.length; i++) {
|
||||||
|
if (infraConfigs[i].name === InfraConfigEnumForClient.MAILER_SMTP_URL) {
|
||||||
|
const isValidUrl = validateUrl(infraConfigs[i].value);
|
||||||
|
if (!isValidUrl) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return E.right(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
JSON_INVALID,
|
JSON_INVALID,
|
||||||
} from './errors';
|
} from './errors';
|
||||||
import { AuthProvider } from './auth/helper';
|
import { AuthProvider } from './auth/helper';
|
||||||
import { ConfigService } from '@nestjs/config';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A workaround to throw an exception in an expression.
|
* A workaround to throw an exception in an expression.
|
||||||
@@ -132,6 +131,41 @@ export const validateEmail = (email: string) => {
|
|||||||
).test(email);
|
).test(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the URL is valid or not
|
||||||
|
* @param url The URL to validate
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
export const validateUrl = (url: string) => {
|
||||||
|
/**
|
||||||
|
* RegExps.
|
||||||
|
* A URL must match #1 and then at least one of #2/#3.
|
||||||
|
* Use two levels of REs to avoid REDOS.
|
||||||
|
*/
|
||||||
|
const protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
|
||||||
|
const localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
|
||||||
|
const nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;
|
||||||
|
|
||||||
|
const match = url.match(protocolAndDomainRE);
|
||||||
|
if (!match) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const everythingAfterProtocol = match[1];
|
||||||
|
if (!everythingAfterProtocol) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
localhostDomainRE.test(everythingAfterProtocol) ||
|
||||||
|
nonLocalhostDomainRE.test(everythingAfterProtocol)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String to JSON parser
|
* String to JSON parser
|
||||||
* @param {str} str The string to parse
|
* @param {str} str The string to parse
|
||||||
|
|||||||
Reference in New Issue
Block a user