fix: accept new ssh host keys

This commit is contained in:
Peter Steinberger
2025-12-20 21:06:21 +01:00
parent 2bcdf741f9
commit 8fe0b72a04
3 changed files with 23 additions and 4 deletions

View File

@@ -526,7 +526,7 @@ extension GeneralSettings {
timeout: 8) timeout: 8)
guard sshResult.ok else { guard sshResult.ok else {
self.remoteStatus = .failed(self.formatSSHFailure(sshResult)) self.remoteStatus = .failed(self.formatSSHFailure(sshResult, target: settings.target))
return return
} }
@@ -558,7 +558,13 @@ extension GeneralSettings {
} }
private static func sshCheckCommand(target: String, identity: String) -> [String] { private static func sshCheckCommand(target: String, identity: String) -> [String] {
var args: [String] = ["/usr/bin/ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=5"] var args: [String] = [
"/usr/bin/ssh",
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=5",
"-o", "StrictHostKeyChecking=accept-new",
"-o", "UpdateHostKeys=yes",
]
if !identity.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { if !identity.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
args.append(contentsOf: ["-i", identity]) args.append(contentsOf: ["-i", identity])
} }
@@ -567,12 +573,18 @@ extension GeneralSettings {
return args return args
} }
private func formatSSHFailure(_ response: Response) -> String { private func formatSSHFailure(_ response: Response, target: String) -> String {
let payload = response.payload.flatMap { String(data: $0, encoding: .utf8) } let payload = response.payload.flatMap { String(data: $0, encoding: .utf8) }
let trimmed = payload? let trimmed = payload?
.trimmingCharacters(in: .whitespacesAndNewlines) .trimmingCharacters(in: .whitespacesAndNewlines)
.split(whereSeparator: \.isNewline) .split(whereSeparator: \.isNewline)
.joined(separator: " ") .joined(separator: " ")
if let trimmed,
trimmed.localizedCaseInsensitiveContains("host key verification failed")
{
let host = CommandResolver.parseSSHTarget(target)?.host ?? target
return "SSH check failed: Host key verification failed. Remove the old key with `ssh-keygen -R \(host)` and try again."
}
if let trimmed, !trimmed.isEmpty { if let trimmed, !trimmed.isEmpty {
if let message = response.message, message.hasPrefix("exit ") { if let message = response.message, message.hasPrefix("exit ") {
return "SSH check failed: \(trimmed) (\(message))" return "SSH check failed: \(trimmed) (\(message))"

View File

@@ -52,6 +52,8 @@ final class RemotePortTunnel {
"-o", "BatchMode=yes", "-o", "BatchMode=yes",
"-o", "IdentitiesOnly=yes", "-o", "IdentitiesOnly=yes",
"-o", "ExitOnForwardFailure=yes", "-o", "ExitOnForwardFailure=yes",
"-o", "StrictHostKeyChecking=accept-new",
"-o", "UpdateHostKeys=yes",
"-o", "ServerAliveInterval=15", "-o", "ServerAliveInterval=15",
"-o", "ServerAliveCountMax=3", "-o", "ServerAliveCountMax=3",
"-o", "TCPKeepAlive=yes", "-o", "TCPKeepAlive=yes",

View File

@@ -469,7 +469,12 @@ enum CommandResolver {
guard !settings.target.isEmpty else { return nil } guard !settings.target.isEmpty else { return nil }
guard let parsed = self.parseSSHTarget(settings.target) else { return nil } guard let parsed = self.parseSSHTarget(settings.target) else { return nil }
var args: [String] = ["-o", "BatchMode=yes", "-o", "IdentitiesOnly=yes"] var args: [String] = [
"-o", "BatchMode=yes",
"-o", "IdentitiesOnly=yes",
"-o", "StrictHostKeyChecking=accept-new",
"-o", "UpdateHostKeys=yes",
]
if parsed.port > 0 { args.append(contentsOf: ["-p", String(parsed.port)]) } if parsed.port > 0 { args.append(contentsOf: ["-p", String(parsed.port)]) }
if !settings.identity.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { if !settings.identity.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
args.append(contentsOf: ["-i", settings.identity]) args.append(contentsOf: ["-i", settings.identity])