HSB-473 feat: encrypt sensitive data before storing in db (#4212)
* feat: encryption added on onMuduleInit * feat: encryption changes added on sh admin mutations and query * chore: fetch minimum column from DB * feat: data encryption added on account table * test: infra config test case update * chore: env example modified * chore: update variable name * chore: refactor the code * feat: client-ids made encrypted * chore: encrypted auth client id's --------- Co-authored-by: Balu Babu <balub997@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import {
|
||||
} from 'src/errors';
|
||||
import { PrismaService } from 'src/prisma/prisma.service';
|
||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
||||
import { throwErr } from 'src/utils';
|
||||
import { decrypt, encrypt, throwErr } from 'src/utils';
|
||||
import { randomBytes } from 'crypto';
|
||||
|
||||
export enum ServiceStatus {
|
||||
@@ -60,7 +60,11 @@ export async function loadInfraConfiguration() {
|
||||
|
||||
let environmentObject: Record<string, any> = {};
|
||||
infraConfigs.forEach((infraConfig) => {
|
||||
environmentObject[infraConfig.name] = infraConfig.value;
|
||||
if (infraConfig.isEncrypted) {
|
||||
environmentObject[infraConfig.name] = decrypt(infraConfig.value);
|
||||
} else {
|
||||
environmentObject[infraConfig.name] = infraConfig.value;
|
||||
}
|
||||
});
|
||||
|
||||
return { INFRA: environmentObject };
|
||||
@@ -76,119 +80,150 @@ export async function loadInfraConfiguration() {
|
||||
* @returns Array of default infra configs
|
||||
*/
|
||||
export async function getDefaultInfraConfigs(): Promise<
|
||||
{ name: InfraConfigEnum; value: string }[]
|
||||
{ name: InfraConfigEnum; value: string; isEncrypted: boolean }[]
|
||||
> {
|
||||
const prisma = new PrismaService();
|
||||
|
||||
// Prepare rows for 'infra_config' table with default values (from .env) for each 'name'
|
||||
const infraConfigDefaultObjs: { name: InfraConfigEnum; value: string }[] = [
|
||||
const infraConfigDefaultObjs: {
|
||||
name: InfraConfigEnum;
|
||||
value: string;
|
||||
isEncrypted: boolean;
|
||||
}[] = [
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_ENABLE,
|
||||
value: process.env.MAILER_SMTP_ENABLE ?? 'true',
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_USE_CUSTOM_CONFIGS,
|
||||
value: process.env.MAILER_USE_CUSTOM_CONFIGS ?? 'false',
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_URL,
|
||||
value: process.env.MAILER_SMTP_URL,
|
||||
value: encrypt(process.env.MAILER_SMTP_URL),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_ADDRESS_FROM,
|
||||
value: process.env.MAILER_ADDRESS_FROM,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_HOST,
|
||||
value: process.env.MAILER_SMTP_HOST,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_PORT,
|
||||
value: process.env.MAILER_SMTP_PORT,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_SECURE,
|
||||
value: process.env.MAILER_SMTP_SECURE,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_USER,
|
||||
value: process.env.MAILER_SMTP_USER,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_SMTP_PASSWORD,
|
||||
value: process.env.MAILER_SMTP_PASSWORD,
|
||||
value: encrypt(process.env.MAILER_SMTP_PASSWORD),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MAILER_TLS_REJECT_UNAUTHORIZED,
|
||||
value: process.env.MAILER_TLS_REJECT_UNAUTHORIZED,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GOOGLE_CLIENT_ID,
|
||||
value: process.env.GOOGLE_CLIENT_ID,
|
||||
value: encrypt(process.env.GOOGLE_CLIENT_ID),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
||||
value: process.env.GOOGLE_CLIENT_SECRET,
|
||||
value: encrypt(process.env.GOOGLE_CLIENT_SECRET),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GOOGLE_CALLBACK_URL,
|
||||
value: process.env.GOOGLE_CALLBACK_URL,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GOOGLE_SCOPE,
|
||||
value: process.env.GOOGLE_SCOPE,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GITHUB_CLIENT_ID,
|
||||
value: process.env.GITHUB_CLIENT_ID,
|
||||
value: encrypt(process.env.GITHUB_CLIENT_ID),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
||||
value: process.env.GITHUB_CLIENT_SECRET,
|
||||
value: encrypt(process.env.GITHUB_CLIENT_SECRET),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GITHUB_CALLBACK_URL,
|
||||
value: process.env.GITHUB_CALLBACK_URL,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.GITHUB_SCOPE,
|
||||
value: process.env.GITHUB_SCOPE,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
||||
value: process.env.MICROSOFT_CLIENT_ID,
|
||||
value: encrypt(process.env.MICROSOFT_CLIENT_ID),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
||||
value: process.env.MICROSOFT_CLIENT_SECRET,
|
||||
value: encrypt(process.env.MICROSOFT_CLIENT_SECRET),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MICROSOFT_CALLBACK_URL,
|
||||
value: process.env.MICROSOFT_CALLBACK_URL,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MICROSOFT_SCOPE,
|
||||
value: process.env.MICROSOFT_SCOPE,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.MICROSOFT_TENANT,
|
||||
value: process.env.MICROSOFT_TENANT,
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
||||
value: getConfiguredSSOProviders(),
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION,
|
||||
value: false.toString(),
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.ANALYTICS_USER_ID,
|
||||
value: generateAnalyticsUserId(),
|
||||
isEncrypted: false,
|
||||
},
|
||||
{
|
||||
name: InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
||||
value: (await prisma.infraConfig.count()) === 0 ? 'true' : 'false',
|
||||
isEncrypted: false,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -214,12 +249,33 @@ export async function getMissingInfraConfigEntries() {
|
||||
return missingEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encryption required entries in the 'infra_config' table
|
||||
* @returns Array of InfraConfig
|
||||
*/
|
||||
export async function getEncryptionRequiredInfraConfigEntries() {
|
||||
const prisma = new PrismaService();
|
||||
const [dbInfraConfigs, infraConfigDefaultObjs] = await Promise.all([
|
||||
prisma.infraConfig.findMany(),
|
||||
getDefaultInfraConfigs(),
|
||||
]);
|
||||
|
||||
const requiredEncryption = dbInfraConfigs.filter((dbConfig) => {
|
||||
const defaultConfig = infraConfigDefaultObjs.find(
|
||||
(config) => config.name === dbConfig.name,
|
||||
);
|
||||
if (!defaultConfig) return false;
|
||||
return defaultConfig.isEncrypted !== dbConfig.isEncrypted;
|
||||
});
|
||||
|
||||
return requiredEncryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if 'infra_config' table is loaded with all entries
|
||||
* @returns boolean
|
||||
*/
|
||||
export async function isInfraConfigTablePopulated(): Promise<boolean> {
|
||||
const prisma = new PrismaService();
|
||||
try {
|
||||
const propsRemainingToInsert = await getMissingInfraConfigEntries();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user