@@ -10,7 +10,7 @@ import TableProPluginKit
1010
1111// MARK: - Error Types
1212
13- enum EtcdError : Error , LocalizedError {
13+ internal enum EtcdError : Error , LocalizedError {
1414 case notConnected
1515 case connectionFailed( String )
1616 case serverError( String )
@@ -35,7 +35,7 @@ enum EtcdError: Error, LocalizedError {
3535
3636// MARK: - Codable Types
3737
38- struct EtcdResponseHeader : Decodable {
38+ internal struct EtcdResponseHeader : Decodable {
3939 let clusterId : String ?
4040 let memberId : String ?
4141 let revision : String ?
@@ -49,7 +49,7 @@ struct EtcdResponseHeader: Decodable {
4949 }
5050}
5151
52- struct EtcdKeyValue : Decodable {
52+ internal struct EtcdKeyValue : Decodable {
5353 let key : String
5454 let value : String ?
5555 let version : String ?
@@ -69,7 +69,7 @@ struct EtcdKeyValue: Decodable {
6969
7070// KV Request/Response
7171
72- struct EtcdRangeRequest : Encodable {
72+ internal struct EtcdRangeRequest : Encodable {
7373 let key : String
7474 var rangeEnd : String ?
7575 var limit : Int64 ?
@@ -89,13 +89,13 @@ struct EtcdRangeRequest: Encodable {
8989 }
9090}
9191
92- struct EtcdRangeResponse : Decodable {
92+ internal struct EtcdRangeResponse : Decodable {
9393 let kvs : [ EtcdKeyValue ] ?
9494 let count : String ?
9595 let more : Bool ?
9696}
9797
98- struct EtcdPutRequest : Encodable {
98+ internal struct EtcdPutRequest : Encodable {
9999 let key : String
100100 let value : String
101101 var lease : String ?
@@ -109,7 +109,7 @@ struct EtcdPutRequest: Encodable {
109109 }
110110}
111111
112- struct EtcdPutResponse : Decodable {
112+ internal struct EtcdPutResponse : Decodable {
113113 let header : EtcdResponseHeader ?
114114 let prevKv : EtcdKeyValue ?
115115
@@ -119,7 +119,7 @@ struct EtcdPutResponse: Decodable {
119119 }
120120}
121121
122- struct EtcdDeleteRequest : Encodable {
122+ internal struct EtcdDeleteRequest : Encodable {
123123 let key : String
124124 var rangeEnd : String ?
125125 var prevKv : Bool ?
@@ -131,7 +131,7 @@ struct EtcdDeleteRequest: Encodable {
131131 }
132132}
133133
134- struct EtcdDeleteResponse : Decodable {
134+ internal struct EtcdDeleteResponse : Decodable {
135135 let deleted : String ?
136136 let prevKvs : [ EtcdKeyValue ] ?
137137
@@ -143,57 +143,57 @@ struct EtcdDeleteResponse: Decodable {
143143
144144// Lease
145145
146- struct EtcdLeaseGrantRequest : Encodable {
146+ internal struct EtcdLeaseGrantRequest : Encodable {
147147 let TTL : String
148148 var ID : String ?
149149}
150150
151- struct EtcdLeaseGrantResponse : Decodable {
151+ internal struct EtcdLeaseGrantResponse : Decodable {
152152 let ID : String ?
153153 let TTL : String ?
154154 let error : String ?
155155}
156156
157- struct EtcdLeaseRevokeRequest : Encodable {
157+ internal struct EtcdLeaseRevokeRequest : Encodable {
158158 let ID : String
159159}
160160
161- struct EtcdLeaseTimeToLiveRequest : Encodable {
161+ internal struct EtcdLeaseTimeToLiveRequest : Encodable {
162162 let ID : String
163163 let keys : Bool ?
164164}
165165
166- struct EtcdLeaseTimeToLiveResponse : Decodable {
166+ internal struct EtcdLeaseTimeToLiveResponse : Decodable {
167167 let ID : String ?
168168 let TTL : String ?
169169 let grantedTTL : String ?
170170 let keys : [ String ] ?
171171}
172172
173- struct EtcdLeaseListResponse : Decodable {
173+ internal struct EtcdLeaseListResponse : Decodable {
174174 let leases : [ EtcdLeaseStatus ] ?
175175}
176176
177- struct EtcdLeaseStatus : Decodable {
177+ internal struct EtcdLeaseStatus : Decodable {
178178 let ID : String
179179}
180180
181181// Cluster
182182
183- struct EtcdMemberListResponse : Decodable {
183+ internal struct EtcdMemberListResponse : Decodable {
184184 let members : [ EtcdMember ] ?
185185 let header : EtcdResponseHeader ?
186186}
187187
188- struct EtcdMember : Decodable {
188+ internal struct EtcdMember : Decodable {
189189 let ID : String ?
190190 let name : String ?
191191 let peerURLs : [ String ] ?
192192 let clientURLs : [ String ] ?
193193 let isLearner : Bool ?
194194}
195195
196- struct EtcdStatusResponse : Decodable {
196+ internal struct EtcdStatusResponse : Decodable {
197197 let version : String ?
198198 let dbSize : String ?
199199 let leader : String ?
@@ -204,15 +204,15 @@ struct EtcdStatusResponse: Decodable {
204204
205205// Watch
206206
207- struct EtcdWatchRequest : Encodable {
207+ internal struct EtcdWatchRequest : Encodable {
208208 let createRequest : EtcdWatchCreateRequest
209209
210210 private enum CodingKeys : String , CodingKey {
211211 case createRequest = " create_request "
212212 }
213213}
214214
215- struct EtcdWatchCreateRequest : Encodable {
215+ internal struct EtcdWatchCreateRequest : Encodable {
216216 let key : String
217217 var rangeEnd : String ?
218218
@@ -222,16 +222,16 @@ struct EtcdWatchCreateRequest: Encodable {
222222 }
223223}
224224
225- struct EtcdWatchStreamResponse : Decodable {
225+ internal struct EtcdWatchStreamResponse : Decodable {
226226 let result : EtcdWatchResult ?
227227}
228228
229- struct EtcdWatchResult : Decodable {
229+ internal struct EtcdWatchResult : Decodable {
230230 let events : [ EtcdWatchEvent ] ?
231231 let header : EtcdResponseHeader ?
232232}
233233
234- struct EtcdWatchEvent : Decodable {
234+ internal struct EtcdWatchEvent : Decodable {
235235 let type : String ?
236236 let kv : EtcdKeyValue ?
237237 let prevKv : EtcdKeyValue ?
@@ -245,53 +245,53 @@ struct EtcdWatchEvent: Decodable {
245245
246246// Auth
247247
248- struct EtcdAuthRequest : Encodable {
248+ internal struct EtcdAuthRequest : Encodable {
249249 let name : String
250250 let password : String
251251}
252252
253- struct EtcdAuthResponse : Decodable {
253+ internal struct EtcdAuthResponse : Decodable {
254254 let token : String ?
255255}
256256
257- struct EtcdUserAddRequest : Encodable {
257+ internal struct EtcdUserAddRequest : Encodable {
258258 let name : String
259259 let password : String
260260}
261261
262- struct EtcdUserDeleteRequest : Encodable {
262+ internal struct EtcdUserDeleteRequest : Encodable {
263263 let name : String
264264}
265265
266- struct EtcdUserListResponse : Decodable {
266+ internal struct EtcdUserListResponse : Decodable {
267267 let users : [ String ] ?
268268}
269269
270- struct EtcdRoleAddRequest : Encodable {
270+ internal struct EtcdRoleAddRequest : Encodable {
271271 let name : String
272272}
273273
274- struct EtcdRoleDeleteRequest : Encodable {
274+ internal struct EtcdRoleDeleteRequest : Encodable {
275275 let name : String
276276}
277277
278- struct EtcdRoleListResponse : Decodable {
278+ internal struct EtcdRoleListResponse : Decodable {
279279 let roles : [ String ] ?
280280}
281281
282- struct EtcdUserGrantRoleRequest : Encodable {
282+ internal struct EtcdUserGrantRoleRequest : Encodable {
283283 let user : String
284284 let role : String
285285}
286286
287- struct EtcdUserRevokeRoleRequest : Encodable {
287+ internal struct EtcdUserRevokeRoleRequest : Encodable {
288288 let user : String
289289 let role : String
290290}
291291
292292// Maintenance
293293
294- struct EtcdCompactionRequest : Encodable {
294+ internal struct EtcdCompactionRequest : Encodable {
295295 let revision : String
296296 let physical : Bool ?
297297}
@@ -306,7 +306,7 @@ private struct EtcdErrorResponse: Decodable {
306306
307307// MARK: - HTTP Client
308308
309- final class EtcdHttpClient : @unchecked Sendable {
309+ internal final class EtcdHttpClient : @unchecked Sendable {
310310 private let config : DriverConnectionConfig
311311 private let lock = NSLock ( )
312312 private var session : URLSession ?
@@ -344,12 +344,8 @@ final class EtcdHttpClient: @unchecked Sendable {
344344 let delegate : URLSessionDelegate ?
345345 switch tlsMode {
346346 case " Required " :
347- delegate = EtcdTlsDelegate (
348- caCertPath: nil ,
349- clientCertPath: config. additionalFields [ " etcdClientCertPath " ] ,
350- clientKeyPath: config. additionalFields [ " etcdClientKeyPath " ] ,
351- verifyHostname: false
352- )
347+ // Encryption without certificate verification — matches UI "Required (skip verify)"
348+ delegate = InsecureTlsDelegate ( )
353349 case " VerifyCA " , " VerifyIdentity " :
354350 delegate = EtcdTlsDelegate (
355351 caCertPath: config. additionalFields [ " etcdCaCertPath " ] ,
@@ -505,15 +501,15 @@ final class EtcdHttpClient: @unchecked Sendable {
505501 self . lock. lock ( )
506502 self . currentTask = task
507503 self . lock. unlock ( )
508- collectedData. task = task
504+ collectedData. setTask ( task)
509505 task. resume ( )
510506 }
511507 return Self . parseWatchEvents ( from: data)
512508 }
513509
514510 group. addTask {
515511 try await Task . sleep ( nanoseconds: UInt64 ( timeout * 1_000_000_000 ) )
516- collectedData. task ? . cancel ( )
512+ collectedData. cancelTask ( )
517513 return [ ]
518514 }
519515
@@ -827,7 +823,21 @@ final class EtcdHttpClient: @unchecked Sendable {
827823 // MARK: - Data Collector for Watch
828824
829825 private final class DataCollector : @unchecked Sendable {
830- var task : URLSessionDataTask ?
826+ private let lock = NSLock ( )
827+ private var _task : URLSessionDataTask ?
828+
829+ func setTask( _ task: URLSessionDataTask ) {
830+ lock. lock ( )
831+ _task = task
832+ lock. unlock ( )
833+ }
834+
835+ func cancelTask( ) {
836+ lock. lock ( )
837+ let task = _task
838+ lock. unlock ( )
839+ task? . cancel ( )
840+ }
831841 }
832842
833843 // MARK: - TLS Delegates
@@ -945,8 +955,10 @@ final class EtcdHttpClient: @unchecked Sendable {
945955 return
946956 }
947957
948- // swiftlint:disable:next force_cast
949- let identity = identityRef as! SecIdentity
958+ guard let identity = identityRef as? SecIdentity else {
959+ completionHandler ( . cancelAuthenticationChallenge, nil )
960+ return
961+ }
950962 let credential = URLCredential (
951963 identity: identity,
952964 certificates: nil ,
@@ -1027,38 +1039,42 @@ final class EtcdHttpClient: @unchecked Sendable {
10271039 }
10281040
10291041 private func createIdentity( certificate: SecCertificate , privateKey: SecKey ) -> SecIdentity ? {
1030- // Add cert and key to a temporary keychain to get an identity
1042+ // Add cert and key to the keychain temporarily to create an identity
10311043 let addCertQuery : [ String : Any ] = [
10321044 kSecClass as String : kSecClassCertificate,
10331045 kSecValueRef as String : certificate,
10341046 kSecReturnRef as String : true
10351047 ]
10361048 var certRef : CFTypeRef ?
1037- SecItemAdd ( addCertQuery as CFDictionary , & certRef)
1049+ let certAddStatus = SecItemAdd ( addCertQuery as CFDictionary , & certRef)
10381050
10391051 let addKeyQuery : [ String : Any ] = [
10401052 kSecClass as String : kSecClassKey,
10411053 kSecValueRef as String : privateKey,
10421054 kSecReturnRef as String : true
10431055 ]
10441056 var keyRef : CFTypeRef ?
1045- SecItemAdd ( addKeyQuery as CFDictionary , & keyRef)
1057+ let keyAddStatus = SecItemAdd ( addKeyQuery as CFDictionary , & keyRef)
10461058
10471059 var identity : SecIdentity ?
10481060 let status = SecIdentityCreateWithCertificate ( nil , certificate, & identity)
10491061
1050- // Clean up: remove imported items from keychain
1051- let deleteCertQuery : [ String : Any ] = [
1052- kSecClass as String : kSecClassCertificate,
1053- kSecValueRef as String : certificate
1054- ]
1055- SecItemDelete ( deleteCertQuery as CFDictionary )
1062+ // Clean up: only delete items that this call actually inserted
1063+ if certAddStatus == errSecSuccess {
1064+ let deleteCertQuery : [ String : Any ] = [
1065+ kSecClass as String : kSecClassCertificate,
1066+ kSecValueRef as String : certRef ?? certificate
1067+ ]
1068+ SecItemDelete ( deleteCertQuery as CFDictionary )
1069+ }
10561070
1057- let deleteKeyQuery : [ String : Any ] = [
1058- kSecClass as String : kSecClassKey,
1059- kSecValueRef as String : privateKey
1060- ]
1061- SecItemDelete ( deleteKeyQuery as CFDictionary )
1071+ if keyAddStatus == errSecSuccess {
1072+ let deleteKeyQuery : [ String : Any ] = [
1073+ kSecClass as String : kSecClassKey,
1074+ kSecValueRef as String : keyRef ?? privateKey
1075+ ]
1076+ SecItemDelete ( deleteKeyQuery as CFDictionary )
1077+ }
10621078
10631079 if status == errSecSuccess {
10641080 return identity
0 commit comments