diff --git a/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java b/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java index 6588f6bf1..5f428ee63 100644 --- a/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java +++ b/agents/drivers/dameng/src/main/java/com/dbx/agent/dameng/DamengAgent.java @@ -1089,7 +1089,17 @@ public final class DamengAgent extends BaseDatabaseAgent { private static String buildUrl(ConnectParams params) { String database = params.getDatabase() == null ? "" : params.getDatabase().trim(); String suffix = database.isEmpty() ? "" : "/" + database; - return "jdbc:dm://" + params.getHost() + ":" + params.getPort() + suffix; + String url = "jdbc:dm://" + params.getHost() + ":" + params.getPort() + suffix; + String urlParams = params.getUrl_params() == null ? "" : params.getUrl_params().trim(); + while (urlParams.startsWith("?") || urlParams.startsWith("&") || urlParams.startsWith(";")) { + urlParams = urlParams.substring(1); + } + if (urlParams.isEmpty()) { + return url; + } + + // DM8 SSL options are JDBC URL query parameters; dropping them makes the driver initialize SSL with defaults. + return url + "?" + urlParams; } private static String formatDataType( diff --git a/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentUrlTest.java b/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentUrlTest.java index c1d72a87b..8322c4308 100644 --- a/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentUrlTest.java +++ b/agents/drivers/dameng/src/test/java/com/dbx/agent/dameng/DamengAgentUrlTest.java @@ -21,6 +21,25 @@ class DamengAgentUrlTest { Assertions.assertEquals("jdbc:dm://127.0.0.1:5236/MAIN", url); } + @Test + void appendsDmJdbcUrlParameters() throws Exception { + String url = invokeBuildUrl(new ConnectParams( + "127.0.0.1", + 5236, + "", + "SYSDBA", + "pwd", + "?sslFilesPath=/Users/test/dmcert&sslkeystorePass=secret", + "", + false + )); + + Assertions.assertEquals( + "jdbc:dm://127.0.0.1:5236?sslFilesPath=/Users/test/dmcert&sslkeystorePass=secret", + url + ); + } + private static String invokeBuildUrl(ConnectParams params) throws Exception { Method method = DamengAgent.class.getDeclaredMethod("buildUrl", ConnectParams.class); method.setAccessible(true); diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue index be5bf35c3..75b85f48d 100644 --- a/apps/desktop/src/components/connection/ConnectionDialog.vue +++ b/apps/desktop/src/components/connection/ConnectionDialog.vue @@ -39,6 +39,7 @@ import { isLocalFileTypeDb } from "@/lib/connection/connectionFile"; import { MQ_PINNED_VERSION_OPTIONS, pinnedVersionToSelection, selectionToPinnedVersion } from "@/lib/mq/mqPinnedVersionOptions"; import { mongodbAuthFailureHint, mongoUrlParam, mongoUrlParamIsTrue, normalizeMongoTlsFormState, setMongoUrlParam, setMongoUrlParamBoolean } from "@/lib/mongo/mongoConnectionOptions"; import { mysqlCleartextPasswordAuthEnabled, setMysqlCleartextPasswordAuthEnabled } from "@/lib/database/mysqlConnectionOptions"; +import { applyDamengSslUrlParams, damengSslFormConfig } from "@/lib/database/damengSslOptions"; import { copyToClipboard } from "@/lib/common/clipboard"; import { configuredDatabaseProductName, connectionConfigFingerprint, databaseInfoCopyText, databaseInfoRows, normalizeDatabaseConnectionInfo, type DatabaseInfoField } from "@/lib/connection/connectionDatabaseInfo"; import { agentDriverInstallKey, appendAgentDriverUpdateHint, hasAgentDriverUpdate, showAgentDriverInstallHint, type AgentDriverInstallState, type DriverStoreFocus } from "@/lib/connection/agentDriverInstallHint"; @@ -2434,7 +2435,7 @@ const sqliteExtensionPaths = computed({ form.value.url_params = setSqliteExtensionPaths(form.value.url_params, value); }, }); -const tlsCapableDatabaseTypes = new Set(["mysql", "starrocks", "postgres", "redshift", "gaussdb", "kwdb", "opengauss", "questdb", "redis", "etcd", "clickhouse", "elasticsearch", "qdrant", "milvus", "weaviate", "chromadb", "influxdb"]); +const tlsCapableDatabaseTypes = new Set(["mysql", "starrocks", "postgres", "redshift", "gaussdb", "kwdb", "opengauss", "questdb", "dameng", "redis", "etcd", "clickhouse", "elasticsearch", "qdrant", "milvus", "weaviate", "chromadb", "influxdb"]); const supportsTlsToggle = computed(() => tlsCapableDatabaseTypes.has(form.value.db_type)); const supportsCaCertificatePath = computed(() => form.value.db_type === "clickhouse"); const supportsGenericUrlParams = computed(() => form.value.db_type !== "manticoresearch"); @@ -2447,6 +2448,37 @@ const mysqlCleartextPasswordAuth = computed({ form.value.url_params = setMysqlCleartextPasswordAuthEnabled(form.value.url_params, value); }, }); +// DM8 configures SSL through JDBC URL parameters, so the TLS form and Advanced tab share one source of truth. +const tlsEnabled = computed({ + get: () => !!form.value.ssl || (form.value.db_type === "dameng" && damengSslFormConfig(form.value.url_params).enabled), + set: (enabled: boolean) => { + form.value.ssl = enabled; + if (form.value.db_type === "dameng" && !enabled) { + form.value.url_params = applyDamengSslUrlParams(form.value.url_params, false, "", "", ""); + } + }, +}); +const damengSslFilesPath = computed({ + get: () => damengSslFormConfig(form.value.url_params).sslFilesPath, + set: (value: string) => { + const current = damengSslFormConfig(form.value.url_params); + form.value.url_params = applyDamengSslUrlParams(form.value.url_params, true, value, current.sslKeystorePassword, current.sslProtocol); + }, +}); +const damengSslKeystorePassword = computed({ + get: () => damengSslFormConfig(form.value.url_params).sslKeystorePassword, + set: (value: string) => { + const current = damengSslFormConfig(form.value.url_params); + form.value.url_params = applyDamengSslUrlParams(form.value.url_params, true, current.sslFilesPath, value, current.sslProtocol); + }, +}); +const damengSslProtocol = computed({ + get: () => damengSslFormConfig(form.value.url_params).sslProtocol, + set: (value: string) => { + const current = damengSslFormConfig(form.value.url_params); + form.value.url_params = applyDamengSslUrlParams(form.value.url_params, true, current.sslFilesPath, current.sslKeystorePassword, value); + }, +}); const mysqlTlsMode = computed({ get: () => mysqlTlsModeFromParams(form.value.url_params, form.value.ssl), set: (value: string) => { @@ -3020,6 +3052,11 @@ function connectionConfigForSubmit(id: string, generatedName = ""): ConnectionCo if (config.db_type === "manticoresearch") { config.url_params = ""; } + if (config.db_type === "dameng") { + const damengSsl = damengSslFormConfig(config.url_params); + config.ssl = !!config.ssl || damengSsl.enabled; + config.url_params = applyDamengSslUrlParams(config.url_params, config.ssl, damengSsl.sslFilesPath, damengSsl.sslKeystorePassword, damengSsl.sslProtocol); + } if (config.db_type === "hive") { if (hiveAuthMode.value === "kerberos" && !hivePrincipal.value.trim()) { throw new Error(t("connection.hiveKerberosPrincipalRequired")); @@ -4201,6 +4238,20 @@ async function browseCaCertPath() { } } +async function browseDamengSslFilesPath() { + if (isTauriRuntime()) { + const { open } = await import("@tauri-apps/plugin-dialog"); + const selected = await open({ + title: t("connection.damengSslFilesPathBrowse"), + directory: true, + multiple: false, + }); + if (selected && typeof selected === "string") { + damengSslFilesPath.value = selected; + } + } +} + async function browseMysqlTlsFile(target: "cert" | "key") { if (isTauriRuntime()) { const { open } = await import("@tauri-apps/plugin-dialog"); @@ -6044,11 +6095,46 @@ function openExternalUrl(url: string) {
+ +