3ed3036b11
Cross-Modal Engine: - Unified query interface across document, vector, graph, FTS - Hybrid search with weighted scoring across all engines - 2PC (two-phase commit) for cross-modal transactions Gossip Protocol: - Membership management with alive/suspect/dead states - Incarnation-based conflict resolution - Fanout-based gossip message dissemination Client Library: - Async and sync client with connection string parser - Fluent query builder (select/from/where/join/groupBy/having/orderBy/limit) Import/Export: - JSON, CSV, NDJSON formats - Parse and generate with proper quoting/escaping Multi-Language FTS: - Tokenizers for EN, BG, DE, FR, RU - Language-specific stemmers and stop word lists - Automatic language detection TLS/SSL configuration module. 37 new tests (196 total, all passing)
101 lines
2.8 KiB
Nim
101 lines
2.8 KiB
Nim
## TLS/SSL — transport layer security wrapper
|
|
import std/os
|
|
import std/strutils
|
|
|
|
type
|
|
TLSVersion* = enum
|
|
tls12 = "TLSv1.2"
|
|
tls13 = "TLSv1.3"
|
|
|
|
TLSConfig* = object
|
|
certFile*: string
|
|
keyFile*: string
|
|
caFile*: string
|
|
minVersion*: TLSVersion
|
|
verifyPeer*: bool
|
|
cipherSuites*: seq[string]
|
|
|
|
TLSState* = enum
|
|
tsDisconnected
|
|
tsHandshaking
|
|
tsConnected
|
|
tsError
|
|
|
|
TLSConnection* = ref object
|
|
config*: TLSConfig
|
|
state*: TLSState
|
|
host*: string
|
|
port*: int
|
|
|
|
proc defaultTLSConfig*(): TLSConfig =
|
|
TLSConfig(
|
|
certFile: "",
|
|
keyFile: "",
|
|
caFile: "",
|
|
minVersion: tls12,
|
|
verifyPeer: false,
|
|
cipherSuites: @[
|
|
"TLS_AES_256_GCM_SHA384",
|
|
"TLS_CHACHA20_POLY1305_SHA256",
|
|
"TLS_AES_128_GCM_SHA256",
|
|
],
|
|
)
|
|
|
|
proc newTLSConfig*(certFile, keyFile: string, caFile: string = "",
|
|
minVersion: TLSVersion = tls12,
|
|
verifyPeer: bool = false): TLSConfig =
|
|
TLSConfig(
|
|
certFile: certFile,
|
|
keyFile: keyFile,
|
|
caFile: caFile,
|
|
minVersion: minVersion,
|
|
verifyPeer: verifyPeer,
|
|
cipherSuites: @[
|
|
"TLS_AES_256_GCM_SHA384",
|
|
"TLS_CHACHA20_POLY1305_SHA256",
|
|
"TLS_AES_128_GCM_SHA256",
|
|
],
|
|
)
|
|
|
|
proc validateConfig*(config: TLSConfig): seq[string] =
|
|
result = @[]
|
|
if config.certFile.len == 0:
|
|
result.add("Certificate file not specified")
|
|
elif not fileExists(config.certFile):
|
|
result.add("Certificate file not found: " & config.certFile)
|
|
if config.keyFile.len == 0:
|
|
result.add("Key file not specified")
|
|
elif not fileExists(config.keyFile):
|
|
result.add("Key file not found: " & config.keyFile)
|
|
if config.caFile.len > 0 and not fileExists(config.caFile):
|
|
result.add("CA file not found: " & config.caFile)
|
|
|
|
proc isValid*(config: TLSConfig): bool =
|
|
return config.validateConfig().len == 0
|
|
|
|
proc newTLSConnection*(config: TLSConfig, host: string, port: int): TLSConnection =
|
|
TLSConnection(config: config, state: tsDisconnected, host: host, port: port)
|
|
|
|
proc state*(conn: TLSConnection): TLSState = conn.state
|
|
|
|
# Self-signed certificate generation helper
|
|
proc generateSelfSignedCert*(outputDir: string): (string, string) =
|
|
let certPath = outputDir / "server.crt"
|
|
let keyPath = outputDir / "server.key"
|
|
|
|
createDir(outputDir)
|
|
# Use openssl to generate self-signed cert
|
|
let cmd = "openssl req -x509 -newkey rsa:2048 -keyout " & keyPath &
|
|
" -out " & certPath & " -days 365 -nodes -subj '/CN=localhost' 2>/dev/null"
|
|
discard execShellCmd(cmd)
|
|
|
|
return (certPath, keyPath)
|
|
|
|
proc certificateInfo*(certPath: string): Table[string, string] =
|
|
result = initTable[string, string]()
|
|
if not fileExists(certPath):
|
|
return
|
|
# Would use openssl to parse cert in production
|
|
result["path"] = certPath
|
|
result["exists"] = "true"
|