From db6c11dd233b6f38bf862c574f5573a991079863 Mon Sep 17 00:00:00 2001 From: Nikhil-Doye Date: Mon, 20 Oct 2025 14:52:30 -0400 Subject: [PATCH] Enhance DatabaseConnectionManager with credential validation and connection handling - Added credential validation methods for MongoDB, MySQL, and PostgreSQL connections to ensure required fields are present and correctly formatted. - Implemented checks to validate credentials during connection creation and updates, improving error handling and user feedback. - Refactored connection configuration to streamline the creation of database connectors, enhancing maintainability and clarity in the codebase. --- src/services/databaseConnectionManager.ts | 190 ++++++++++++++++++++-- 1 file changed, 177 insertions(+), 13 deletions(-) diff --git a/src/services/databaseConnectionManager.ts b/src/services/databaseConnectionManager.ts index 810649f..5f4d914 100644 --- a/src/services/databaseConnectionManager.ts +++ b/src/services/databaseConnectionManager.ts @@ -39,6 +39,9 @@ class DatabaseConnectionManager { async addConnection( connection: Omit ): Promise { + // Validate credentials before creating the connection + this.validateCredentials(connection as DatabaseConnection); + const id = `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const newConnection: DatabaseConnection = { ...connection, @@ -59,6 +62,12 @@ class DatabaseConnectionManager { if (!connection) return false; const updatedConnection = { ...connection, ...updates }; + + // Validate credentials if connection details are being updated + if (this.hasConnectionDetailsChanged(updates)) { + this.validateCredentials(updatedConnection); + } + this.connections.set(id, updatedConnection); this.saveConnections(); return true; @@ -241,19 +250,13 @@ class DatabaseConnectionManager { // Private Methods private createConnector(connection: DatabaseConnection): any { - const config = { + // Validate credentials based on database type + this.validateCredentials(connection); + + const baseConfig = { id: connection.id, name: connection.name, type: connection.type, - credentials: { - host: connection.host, - port: connection.port, - database: connection.database, - username: connection.username, - password: connection.password, - connectionString: connection.connectionString, - ssl: connection.ssl, - }, settings: { connectionTimeout: 30000, queryTimeout: 60000, @@ -262,16 +265,177 @@ class DatabaseConnectionManager { switch (connection.type) { case "mongodb": - return new MongoConnector(config as any); + return new MongoConnector({ + ...baseConfig, + credentials: { + connectionString: connection.connectionString!, + database: connection.database, + username: connection.username, + password: connection.password, + }, + } as any); case "mysql": - return new MySQLConnector(config as any); + return new MySQLConnector({ + ...baseConfig, + credentials: { + host: connection.host, + port: connection.port, + database: connection.database, + username: connection.username!, + password: connection.password!, + ssl: connection.ssl, + }, + } as any); case "postgresql": - return new PostgresConnector(config as any); + return new PostgresConnector({ + ...baseConfig, + credentials: { + host: connection.host, + port: connection.port, + database: connection.database, + username: connection.username!, + password: connection.password!, + ssl: connection.ssl, + }, + } as any); default: throw new Error(`Unsupported database type: ${connection.type}`); } } + private validateCredentials(connection: DatabaseConnection): void { + switch (connection.type) { + case "mongodb": + this.validateMongoCredentials(connection); + break; + case "mysql": + this.validateMySQLCredentials(connection); + break; + case "postgresql": + this.validatePostgresCredentials(connection); + break; + default: + throw new Error(`Unsupported database type: ${connection.type}`); + } + } + + private validateMongoCredentials(connection: DatabaseConnection): void { + const errors: string[] = []; + + // MongoDB primarily uses connection strings + if (!connection.connectionString) { + errors.push( + "MongoDB requires a connection string (e.g., 'mongodb://localhost:27017' or 'mongodb+srv://...')" + ); + } + + // Database name is required + if (!connection.database) { + errors.push("Database name is required for MongoDB connections"); + } + + // Validate connection string format if provided + if (connection.connectionString) { + if (!this.isValidMongoConnectionString(connection.connectionString)) { + errors.push( + "Invalid MongoDB connection string format. Expected format: 'mongodb://host:port' or 'mongodb+srv://cluster'" + ); + } + } + + if (errors.length > 0) { + throw new Error( + `MongoDB connection validation failed:\n${errors.join("\n")}` + ); + } + } + + private validateMySQLCredentials(connection: DatabaseConnection): void { + const errors: string[] = []; + + if (!connection.host) { + errors.push("Host is required for MySQL connections"); + } + + if (!connection.port || connection.port <= 0 || connection.port > 65535) { + errors.push( + "Valid port number (1-65535) is required for MySQL connections" + ); + } + + if (!connection.database) { + errors.push("Database name is required for MySQL connections"); + } + + if (!connection.username) { + errors.push("Username is required for MySQL connections"); + } + + if (!connection.password) { + errors.push("Password is required for MySQL connections"); + } + + if (errors.length > 0) { + throw new Error( + `MySQL connection validation failed:\n${errors.join("\n")}` + ); + } + } + + private validatePostgresCredentials(connection: DatabaseConnection): void { + const errors: string[] = []; + + if (!connection.host) { + errors.push("Host is required for PostgreSQL connections"); + } + + if (!connection.port || connection.port <= 0 || connection.port > 65535) { + errors.push( + "Valid port number (1-65535) is required for PostgreSQL connections" + ); + } + + if (!connection.database) { + errors.push("Database name is required for PostgreSQL connections"); + } + + if (!connection.username) { + errors.push("Username is required for PostgreSQL connections"); + } + + if (!connection.password) { + errors.push("Password is required for PostgreSQL connections"); + } + + if (errors.length > 0) { + throw new Error( + `PostgreSQL connection validation failed:\n${errors.join("\n")}` + ); + } + } + + private isValidMongoConnectionString(connectionString: string): boolean { + // Basic validation for MongoDB connection strings + const mongoPattern = /^mongodb(\+srv)?:\/\//; + return mongoPattern.test(connectionString); + } + + private hasConnectionDetailsChanged( + updates: Partial + ): boolean { + const connectionFields = [ + "type", + "host", + "port", + "database", + "username", + "password", + "connectionString", + "ssl", + ]; + return connectionFields.some((field) => field in updates); + } + private loadConnections(): void { try { const stored = localStorage.getItem("database_connections");