Files
MyGoNavi/internal/db/ssl_mode.go
Syngnat b707c74203 feat(connection): 支持连接 SSL 证书文件配置
- 新增 CA 证书、客户端证书和私钥路径配置
- 为 MySQL、PostgreSQL、ClickHouse、MongoDB、Redis 等连接接入 TLS 证书
- 修正 SSL 模式下证书校验、明文回退和 DER 证书兼容问题
- 补充证书路径保存、RPC 传递和 DSN 生成回归测试
Refs #463
2026-05-15 22:04:20 +08:00

178 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package db
import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"strings"
"GoNavi-Wails/internal/connection"
"GoNavi-Wails/internal/tlsconfig"
)
const (
sslModeDisable = "disable"
sslModePreferred = "preferred"
sslModeRequired = "required"
sslModeSkipVerify = "skip-verify"
)
func normalizeSSLModeValue(raw string) string {
mode := strings.ToLower(strings.TrimSpace(raw))
switch mode {
case "", sslModePreferred, "prefer":
return sslModePreferred
case sslModeRequired, "require", "on", "true", "mandatory", "strict":
return sslModeRequired
case sslModeSkipVerify, "insecure", "skipverify", "skip_verify", "insecure-skip-verify":
return sslModeSkipVerify
case sslModeDisable, "disabled", "off", "false", "none":
return sslModeDisable
default:
return sslModePreferred
}
}
func normalizedSSLMode(config connection.ConnectionConfig) string {
if !config.UseSSL {
return sslModeDisable
}
return normalizeSSLModeValue(config.SSLMode)
}
func shouldTrySSLPreferredFallback(config connection.ConnectionConfig) bool {
return config.UseSSL && normalizeSSLModeValue(config.SSLMode) == sslModePreferred
}
func withSSLDisabled(config connection.ConnectionConfig) connection.ConnectionConfig {
next := config
next.UseSSL = false
next.SSLMode = sslModeDisable
return next
}
func resolveMySQLTLSMode(config connection.ConnectionConfig) string {
switch normalizedSSLMode(config) {
case sslModeDisable:
return "false"
case sslModeRequired:
return "true"
case sslModeSkipVerify:
return "skip-verify"
default:
return "preferred"
}
}
func hasTLSCertificatePaths(config connection.ConnectionConfig) bool {
return strings.TrimSpace(config.SSLCAPath) != "" ||
strings.TrimSpace(config.SSLCertPath) != "" ||
strings.TrimSpace(config.SSLKeyPath) != ""
}
func mysqlTLSConfigName(config connection.ConnectionConfig) string {
sum := sha256.Sum256([]byte(strings.Join([]string{
normalizedSSLMode(config),
strings.TrimSpace(config.SSLCAPath),
strings.TrimSpace(config.SSLCertPath),
strings.TrimSpace(config.SSLKeyPath),
}, "\x00")))
return "gonavi-" + hex.EncodeToString(sum[:8])
}
func resolvePostgresSSLMode(config connection.ConnectionConfig) string {
switch normalizedSSLMode(config) {
case sslModeDisable:
return "disable"
case sslModeRequired:
if strings.TrimSpace(config.SSLCAPath) != "" {
return "verify-ca"
}
return "require"
case sslModeSkipVerify:
return "require"
default:
if strings.TrimSpace(config.SSLCAPath) != "" {
return "verify-ca"
}
return "require"
}
}
func resolveSQLServerTLSSettings(config connection.ConnectionConfig) (encrypt string, trustServerCertificate string) {
switch normalizedSSLMode(config) {
case sslModeDisable:
return "disable", "true"
case sslModeRequired:
return "true", "false"
case sslModeSkipVerify:
return "true", "true"
default:
return "false", "true"
}
}
func applyPostgresSSLPathParams(params interface{ Set(string, string) }, config connection.ConnectionConfig) {
mode := normalizedSSLMode(config)
if mode != sslModeDisable && mode != sslModeSkipVerify && strings.TrimSpace(config.SSLCAPath) != "" {
params.Set("sslrootcert", strings.TrimSpace(config.SSLCAPath))
}
if mode != sslModeDisable && strings.TrimSpace(config.SSLCertPath) != "" {
params.Set("sslcert", strings.TrimSpace(config.SSLCertPath))
}
if mode != sslModeDisable && strings.TrimSpace(config.SSLKeyPath) != "" {
params.Set("sslkey", strings.TrimSpace(config.SSLKeyPath))
}
}
func resolveGenericTLSConfig(config connection.ConnectionConfig) (*tls.Config, error) {
switch normalizedSSLMode(config) {
case sslModeDisable:
return nil, nil
case sslModeRequired:
return tlsconfig.BuildClientConfig(tlsconfig.ClientConfigOptions{
Enabled: true,
CAPath: config.SSLCAPath,
CertPath: config.SSLCertPath,
KeyPath: config.SSLKeyPath,
})
case sslModeSkipVerify:
return tlsconfig.BuildClientConfig(tlsconfig.ClientConfigOptions{
Enabled: true,
InsecureSkipVerify: true,
CAPath: config.SSLCAPath,
CertPath: config.SSLCertPath,
KeyPath: config.SSLKeyPath,
})
default:
// Preferred: 先尝试 TLS为提升兼容性默认跳过证书校验失败时由调用方按需回退明文。
return tlsconfig.BuildClientConfig(tlsconfig.ClientConfigOptions{
Enabled: true,
InsecureSkipVerify: true,
CAPath: config.SSLCAPath,
CertPath: config.SSLCertPath,
KeyPath: config.SSLKeyPath,
})
}
}
func resolveMongoTLSSettings(config connection.ConnectionConfig) (enabled bool, insecure bool) {
switch normalizedSSLMode(config) {
case sslModeDisable:
return false, false
case sslModeRequired:
return true, false
case sslModeSkipVerify:
return true, true
default:
return true, true
}
}
func resolveTDengineNet(config connection.ConnectionConfig) string {
if normalizedSSLMode(config) == sslModeDisable {
return "ws"
}
return "wss"
}