@@ -15,8 +15,7 @@ internal enum HostKeyVerifier {
1515 private static let logger = Logger ( subsystem: " com.TablePro " , category: " HostKeyVerifier " )
1616
1717 /// Verify the host key, prompting the user if needed.
18- /// This method blocks the calling thread while showing UI prompts.
19- /// Must be called from a background thread.
18+ /// Uses `withCheckedContinuation` to await UI prompts without blocking the cooperative thread pool.
2019 /// - Parameters:
2120 /// - keyData: The raw host key bytes from the SSH session
2221 /// - keyType: The key type string (e.g. "ssh-rsa", "ssh-ed25519")
@@ -28,7 +27,7 @@ internal enum HostKeyVerifier {
2827 keyType: String ,
2928 hostname: String ,
3029 port: Int
31- ) throws {
30+ ) async throws {
3231 let result = HostKeyStore . shared. verify (
3332 keyData: keyData,
3433 keyType: keyType,
@@ -43,7 +42,7 @@ internal enum HostKeyVerifier {
4342
4443 case . unknown( let fingerprint, let keyType) :
4544 logger. info ( " Unknown host key for [ \( hostname) ]: \( port) , prompting user " )
46- let accepted = promptUnknownHost (
45+ let accepted = await promptUnknownHost (
4746 hostname: hostname,
4847 port: port,
4948 fingerprint: fingerprint,
@@ -62,7 +61,7 @@ internal enum HostKeyVerifier {
6261
6362 case . mismatch( let expected, let actual) :
6463 logger. warning ( " Host key mismatch for [ \( hostname) ]: \( port) " )
65- let accepted = promptHostKeyMismatch (
64+ let accepted = await promptHostKeyMismatch (
6665 hostname: hostname,
6766 port: port,
6867 expected: expected,
@@ -83,17 +82,14 @@ internal enum HostKeyVerifier {
8382
8483 // MARK: - UI Prompts
8584
86- /// Show a dialog asking the user whether to trust an unknown host
87- /// Blocks the calling thread until the user responds.
85+ /// Show a dialog asking the user whether to trust an unknown host.
86+ /// Suspends until the user responds, without blocking any thread .
8887 private static func promptUnknownHost(
8988 hostname: String ,
9089 port: Int ,
9190 fingerprint: String ,
9291 keyType: String
93- ) -> Bool {
94- let semaphore = DispatchSemaphore ( value: 0 )
95- var accepted = false
96-
92+ ) async -> Bool {
9793 let hostDisplay = " [ \( hostname) ]: \( port) "
9894 let title = String ( localized: " Unknown SSH Host " )
9995 let message = String ( localized: """
@@ -105,7 +101,7 @@ internal enum HostKeyVerifier {
105101 Are you sure you want to continue connecting?
106102 """ )
107103
108- DispatchQueue . main . async {
104+ return await MainActor . run {
109105 let alert = NSAlert ( )
110106 alert. messageText = title
111107 alert. informativeText = message
@@ -114,25 +110,18 @@ internal enum HostKeyVerifier {
114110 alert. addButton ( withTitle: String ( localized: " Cancel " ) )
115111
116112 let response = alert. runModal ( )
117- accepted = ( response == . alertFirstButtonReturn)
118- semaphore. signal ( )
113+ return response == . alertFirstButtonReturn
119114 }
120-
121- semaphore. wait ( )
122- return accepted
123115 }
124116
125- /// Show a warning dialog about a changed host key (potential MITM attack)
126- /// Blocks the calling thread until the user responds.
117+ /// Show a warning dialog about a changed host key (potential MITM attack).
118+ /// Suspends until the user responds, without blocking any thread .
127119 private static func promptHostKeyMismatch(
128120 hostname: String ,
129121 port: Int ,
130122 expected: String ,
131123 actual: String
132- ) -> Bool {
133- let semaphore = DispatchSemaphore ( value: 0 )
134- var accepted = false
135-
124+ ) async -> Bool {
136125 let hostDisplay = " [ \( hostname) ]: \( port) "
137126 let title = String ( localized: " SSH Host Key Changed " )
138127 let message = String ( localized: """
@@ -144,7 +133,7 @@ internal enum HostKeyVerifier {
144133 Current fingerprint: \( actual)
145134 """ )
146135
147- DispatchQueue . main . async {
136+ return await MainActor . run {
148137 let alert = NSAlert ( )
149138 alert. messageText = title
150139 alert. informativeText = message
@@ -157,11 +146,7 @@ internal enum HostKeyVerifier {
157146 alert. buttons [ 0 ] . keyEquivalent = " "
158147
159148 let response = alert. runModal ( )
160- accepted = ( response == . alertFirstButtonReturn)
161- semaphore. signal ( )
149+ return response == . alertFirstButtonReturn
162150 }
163-
164- semaphore. wait ( )
165- return accepted
166151 }
167152}
0 commit comments