refactor(mongodb-credentials): replace SSL terminology with TLS and enhance MongoDB client creation logic

This commit is contained in:
Victor Santos
2025-12-05 19:35:23 -03:00
parent dfbc2ed033
commit 8c3b36f15c
5 changed files with 105 additions and 123 deletions
@@ -1,8 +1,6 @@
/* eslint-disable no-await-in-loop */
import { MongoClient } from "mongodb";
import RE2 from "re2";
import { verifyHostInputValidity } from "@app/ee/services/dynamic-secret/dynamic-secret-fns";
import {
TRotationFactory,
TRotationFactoryGetSecretsPayload,
@@ -10,6 +8,7 @@ import {
TRotationFactoryRevokeCredentials,
TRotationFactoryRotateCredentials
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types";
import { createMongoClient } from "@app/services/app-connection/mongodb/mongodb-connection-fns";
import { DEFAULT_PASSWORD_REQUIREMENTS, generatePassword } from "../shared/utils";
import {
@@ -44,67 +43,10 @@ export const mongodbCredentialsRotationFactory: TRotationFactory<
const passwordRequirement = DEFAULT_PASSWORD_REQUIREMENTS;
// Helper function to create MongoDB client with given credentials
const $createMongoClient = async (
authCredentials: { username: string; password: string },
options?: { validateConnection?: boolean }
): Promise<MongoClient> => {
let normalizedHost = connection.credentials.host.trim();
const srvRegex = new RE2("^mongodb\\+srv:\\/\\/");
const protocolRegex = new RE2("^mongodb:\\/\\/");
const isSrvFromHost = srvRegex.test(normalizedHost);
if (isSrvFromHost) {
normalizedHost = srvRegex.replace(normalizedHost, "");
} else if (protocolRegex.test(normalizedHost)) {
normalizedHost = protocolRegex.replace(normalizedHost, "");
}
const [hostIp] = await verifyHostInputValidity(normalizedHost);
const isSrv = !connection.credentials.port || isSrvFromHost;
const uri = isSrv ? `mongodb+srv://${hostIp}` : `mongodb://${hostIp}:${connection.credentials.port}`;
const clientOptions: {
auth?: { username: string; password?: string };
authSource?: string;
tls?: boolean;
tlsInsecure?: boolean;
ca?: string;
directConnection?: boolean;
} = {
auth: {
username: authCredentials.username,
password: authCredentials.password
},
authSource: isSrv ? undefined : connection.credentials.database,
directConnection: !isSrv
};
if (connection.credentials.sslCertificate) {
clientOptions.tls = true;
clientOptions.ca = connection.credentials.sslCertificate;
}
const client = new MongoClient(uri, clientOptions);
if (options?.validateConnection) {
await client.db(connection.credentials.database).command({ ping: 1 });
}
return client;
};
const $getClient = async () => {
let client: MongoClient | null = null;
try {
client = await $createMongoClient(
{
username: connection.credentials.username,
password: connection.credentials.password
},
{ validateConnection: true }
);
client = await createMongoClient(connection.credentials, { validateConnection: true });
return client;
} catch (err) {
if (client) await client.close();
@@ -115,13 +57,13 @@ export const mongodbCredentialsRotationFactory: TRotationFactory<
const $validateCredentials = async (credentials: TMongoDBCredentialsRotationGeneratedCredentials[number]) => {
let client: MongoClient | null = null;
try {
client = await $createMongoClient(
{
client = await createMongoClient(connection.credentials, {
authCredentials: {
username: credentials.username,
password: credentials.password
},
{ validateConnection: true }
);
validateConnection: true
});
} catch (error) {
throw new Error(redactPasswords(error, [credentials]));
} finally {
@@ -17,11 +17,32 @@ export const getMongoDBConnectionListItem = () => {
};
};
export const validateMongoDBConnectionCredentials = async (config: TMongoDBConnectionConfig) => {
export type TMongoDBConnectionCredentials = {
host: string;
port?: number;
database: string;
username: string;
password: string;
tlsEnabled?: boolean;
tlsRejectUnauthorized?: boolean;
tlsCertificate?: string;
};
export type TCreateMongoClientOptions = {
authCredentials?: { username: string; password: string };
validateConnection?: boolean;
};
const DEFAULT_CONNECTION_TIMEOUT_MS = 10_000;
export const createMongoClient = async (
credentials: TMongoDBConnectionCredentials,
options?: TCreateMongoClientOptions
): Promise<MongoClient> => {
const srvRegex = new RE2("^mongodb\\+srv:\\/\\/");
const protocolRegex = new RE2("^mongodb:\\/\\/");
let normalizedHost = config.credentials.host.trim();
let normalizedHost = credentials.host.trim();
const isSrvFromHost = srvRegex.test(normalizedHost);
if (isSrvFromHost) {
normalizedHost = srvRegex.replace(normalizedHost, "");
@@ -31,41 +52,60 @@ export const validateMongoDBConnectionCredentials = async (config: TMongoDBConne
const [hostIp] = await verifyHostInputValidity(normalizedHost);
let client: MongoClient | null = null;
try {
const isSrv = !config.credentials.port || isSrvFromHost;
const uri = isSrv ? `mongodb+srv://${hostIp}` : `mongodb://${hostIp}:${config.credentials.port}`;
const isSrv = !credentials.port || isSrvFromHost;
const uri = isSrv ? `mongodb+srv://${hostIp}` : `mongodb://${hostIp}:${credentials.port}`;
const clientOptions: {
auth?: { username: string; password?: string };
authSource?: string;
tls?: boolean;
tlsInsecure?: boolean;
ca?: string;
directConnection?: boolean;
} = {
auth: {
username: config.credentials.username,
password: config.credentials.password
},
authSource: isSrv ? undefined : config.credentials.database,
directConnection: !isSrv
};
const authCredentials = options?.authCredentials ?? {
username: credentials.username,
password: credentials.password
};
if (config.credentials.sslEnabled) {
clientOptions.tls = true;
clientOptions.tlsInsecure = !config.credentials.sslRejectUnauthorized;
if (config.credentials.sslCertificate) {
clientOptions.ca = config.credentials.sslCertificate;
}
const clientOptions: {
auth?: { username: string; password?: string };
authSource?: string;
tls?: boolean;
tlsInsecure?: boolean;
ca?: string;
directConnection?: boolean;
connectTimeoutMS?: number;
serverSelectionTimeoutMS?: number;
socketTimeoutMS?: number;
} = {
auth: {
username: authCredentials.username,
password: authCredentials.password
},
authSource: isSrv ? undefined : credentials.database,
directConnection: !isSrv,
connectTimeoutMS: DEFAULT_CONNECTION_TIMEOUT_MS,
serverSelectionTimeoutMS: DEFAULT_CONNECTION_TIMEOUT_MS,
socketTimeoutMS: DEFAULT_CONNECTION_TIMEOUT_MS
};
if (credentials.tlsEnabled) {
clientOptions.tls = true;
clientOptions.tlsInsecure = !credentials.tlsRejectUnauthorized;
if (credentials.tlsCertificate) {
clientOptions.ca = credentials.tlsCertificate;
}
}
client = new MongoClient(uri, clientOptions);
const client = new MongoClient(uri, clientOptions);
if (options?.validateConnection) {
await client
.db(config.credentials.database)
.db(credentials.database)
.command({ ping: 1 })
.then(() => true);
}
return client;
};
export const validateMongoDBConnectionCredentials = async (config: TMongoDBConnectionConfig) => {
let client: MongoClient | null = null;
try {
client = await createMongoClient(config.credentials, { validateConnection: true });
if (client) await client.close();
@@ -17,9 +17,9 @@ export const BaseMongoDBUsernameAndPasswordConnectionSchema = z.object({
password: z.string().min(1),
database: z.string().min(1).trim(),
sslRejectUnauthorized: z.boolean(),
sslEnabled: z.boolean(),
sslCertificate: z
tlsRejectUnauthorized: z.boolean(),
tlsEnabled: z.boolean(),
tlsCertificate: z
.string()
.trim()
.transform((value) => value || undefined)
@@ -43,9 +43,9 @@ export const SanitizedMongoDBConnectionSchema = z.discriminatedUnion("method", [
port: true,
username: true,
database: true,
sslEnabled: true,
sslRejectUnauthorized: true,
sslCertificate: true
tlsEnabled: true,
tlsRejectUnauthorized: true,
tlsCertificate: true
})
})
]);