Skip to content

Commit 773708a

Browse files
committed
fix(plugin-mssql): keep FreeTDSConnection PluginKit-neutral so iOS builds
1 parent fc8e515 commit 773708a

4 files changed

Lines changed: 40 additions & 16 deletions

File tree

Packages/TableProCore/Sources/TableProMSSQLCore/MSSQLCoreError.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import Foundation
22

3+
public enum MSSQLTLSFailureKind: Sendable {
4+
case serverRejectedPlaintext
5+
case serverRequiresPlaintext
6+
case untrustedCertificate
7+
case hostnameMismatch
8+
case clientCertRequired
9+
case cipherMismatch
10+
}
11+
312
public enum MSSQLCoreError: LocalizedError, Sendable {
413
case connectionFailed(String)
514
case notConnected
615
case queryFailed(String)
716
case cancelled
8-
case tlsHandshakeFailed(String)
17+
case tlsHandshakeFailed(kind: MSSQLTLSFailureKind, serverMessage: String)
918

1019
public var errorDescription: String? {
1120
switch self {
@@ -17,8 +26,8 @@ public enum MSSQLCoreError: LocalizedError, Sendable {
1726
return String(format: String(localized: "Query failed: %@"), detail)
1827
case .cancelled:
1928
return String(localized: "Query was cancelled")
20-
case .tlsHandshakeFailed(let detail):
21-
return String(format: String(localized: "TLS handshake failed: %@"), detail)
29+
case .tlsHandshakeFailed(_, let serverMessage):
30+
return String(format: String(localized: "TLS handshake failed: %@"), serverMessage)
2231
}
2332
}
2433
}

Plugins/MSSQLDriverPlugin/FreeTDSConnection.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import CFreeTDS
1313
import Foundation
1414
import os
1515
import TableProMSSQLCore
16-
import TableProPluginKit
1716

1817
private let freetdsLogger = Logger(subsystem: "com.TablePro", category: "FreeTDSConnection")
1918

@@ -167,8 +166,8 @@ nonisolated final class FreeTDSConnection: @unchecked Sendable {
167166
guard let proc = dbopen(login, serverName) else {
168167
let detail = freetdsGetError(for: nil)
169168
let msg = detail.isEmpty ? "Check host, port, credentials, and TLS settings" : detail
170-
if let sslError = FreeTDSConnection.classifySSLError(detail) {
171-
throw sslError
169+
if let kind = FreeTDSConnection.classifySSLError(detail) {
170+
throw MSSQLCoreError.tlsHandshakeFailed(kind: kind, serverMessage: detail)
172171
}
173172
throw MSSQLCoreError.connectionFailed("Failed to connect to \(options.host):\(options.port): \(msg)")
174173
}
@@ -532,22 +531,22 @@ nonisolated final class FreeTDSConnection: @unchecked Sendable {
532531
return raw
533532
}
534533

535-
static func classifySSLError(_ message: String) -> SSLHandshakeError? {
534+
static func classifySSLError(_ message: String) -> MSSQLTLSFailureKind? {
536535
let lower = message.lowercased()
537536
if lower.contains("encryption is required") || lower.contains("server requires encryption") {
538-
return .serverRejectedPlaintext(serverMessage: message)
537+
return .serverRejectedPlaintext
539538
}
540539
if lower.contains("encryption not supported") || lower.contains("server does not support encryption") {
541-
return .serverRequiresPlaintext(serverMessage: message)
540+
return .serverRequiresPlaintext
542541
}
543542
if lower.contains("certificate verify failed") || lower.contains("certificate is not trusted") {
544-
return .untrustedCertificate(serverMessage: message)
543+
return .untrustedCertificate
545544
}
546545
if lower.contains("does not match host") {
547-
return .hostnameMismatch(serverMessage: message)
546+
return .hostnameMismatch
548547
}
549548
if lower.contains("ssl handshake") || lower.contains("tls handshake") || lower.contains("openssl error") {
550-
return .cipherMismatch(serverMessage: message)
549+
return .cipherMismatch
551550
}
552551
return nil
553552
}

Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,21 @@ private extension MSSQLPluginError {
4444
self = .queryFailed(m)
4545
case .cancelled:
4646
self = .queryFailed(String(localized: "Query was cancelled"))
47-
case .tlsHandshakeFailed(let m):
48-
self = .connectionFailed(String(format: String(localized: "TLS: %@"), m))
47+
case .tlsHandshakeFailed(_, let serverMessage):
48+
self = .connectionFailed(String(format: String(localized: "TLS: %@"), serverMessage))
49+
}
50+
}
51+
}
52+
53+
private extension MSSQLTLSFailureKind {
54+
func sslHandshakeError(serverMessage: String) -> SSLHandshakeError {
55+
switch self {
56+
case .serverRejectedPlaintext: return .serverRejectedPlaintext(serverMessage: serverMessage)
57+
case .serverRequiresPlaintext: return .serverRequiresPlaintext(serverMessage: serverMessage)
58+
case .untrustedCertificate: return .untrustedCertificate(serverMessage: serverMessage)
59+
case .hostnameMismatch: return .hostnameMismatch(serverMessage: serverMessage)
60+
case .clientCertRequired: return .clientCertRequired(serverMessage: serverMessage)
61+
case .cipherMismatch: return .cipherMismatch(serverMessage: serverMessage)
4962
}
5063
}
5164
}
@@ -229,6 +242,9 @@ final class MSSQLPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
229242
do {
230243
try await conn.connect()
231244
} catch let error as MSSQLCoreError {
245+
if case let .tlsHandshakeFailed(kind, serverMessage) = error {
246+
throw kind.sslHandshakeError(serverMessage: serverMessage)
247+
}
232248
throw MSSQLPluginError(coreError: error)
233249
}
234250
self.freeTDSConn = conn

TableProMobile/TableProMobile/Drivers/MSSQLDriver.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ final class MSSQLDriver: DatabaseDriver, @unchecked Sendable {
275275
return ConnectionError.notConnected
276276
case .connectionFailed(let msg):
277277
return DatabaseError(message: msg)
278-
case .tlsHandshakeFailed(let msg):
279-
return DatabaseError(message: "TLS handshake failed: \(msg)")
278+
case .tlsHandshakeFailed(_, let serverMessage):
279+
return DatabaseError(message: "TLS handshake failed: \(serverMessage)")
280280
case .queryFailed(let msg):
281281
return DatabaseError(message: msg)
282282
case .cancelled:

0 commit comments

Comments
 (0)