Popup-Fix: sheet(item) statt if-let (leeres Sheet), Keyscan im Hintergrund, Doku

This commit is contained in:
x3
2026-09-22 09:39:26 +02:00
parent 4209c481dc
commit d0855ab45d
3 changed files with 46 additions and 35 deletions
@@ -11,9 +11,7 @@ struct EmbeddedTerminalView: View {
@State private var input = ""
@State private var secureInput = false
@State private var checking = false
@State private var hostKeyInfo: HostKeyInfo?
@State private var hostKeyChange = false
@State private var showingHostKey = false
@State private var hostKeyRequest: HostKeyRequest?
var body: some View {
VStack(spacing: 0) {
@@ -101,17 +99,14 @@ struct EmbeddedTerminalView: View {
connect() // Auto-Connect beim Öffnen des Tabs
}
}
.sheet(isPresented: $showingHostKey) {
if let info = hostKeyInfo {
HostKeySheet(info: info, isChange: hostKeyChange,
onAccept: acceptHostKey,
onCancel: {
showingHostKey = false
checking = false
hostKeyInfo = nil
term.fail("Host-Key nicht akzeptiert — Verbindung abgebrochen.")
})
}
.sheet(item: $hostKeyRequest) { req in
HostKeySheet(info: req.info, isChange: req.isChange,
onAccept: { acceptHostKey(req) },
onCancel: {
hostKeyRequest = nil
checking = false
term.fail("Host-Key nicht akzeptiert — Verbindung abgebrochen.")
})
}
}
@@ -125,40 +120,41 @@ struct EmbeddedTerminalView: View {
term.fail("Vorab-Check: \(message)")
return
}
// Host-Key vorab per keyscan prüfen (Yes/No-Prompt käme ohne Ctty nicht an)
let hk = HostKeyService.status(host: profile.host, port: profile.port)
switch hk {
case .known, .unreachable:
checking = false
term.start()
case .unknown(let info):
hostKeyInfo = info
hostKeyChange = false
showingHostKey = true
case .changed(let info):
hostKeyInfo = info
hostKeyChange = true
showingHostKey = true
// Host-Key vorab per keyscan prüfen (Yes/No-Prompt käme ohne Ctty nicht an).
// Läuft im Hintergrund: ssh-keyscan blockiert Sekunden (kein UI-Freeze).
let host = profile.host
let port = profile.port
DispatchQueue.global(qos: .userInitiated).async {
let hk = HostKeyService.status(host: host, port: port)
DispatchQueue.main.async {
switch hk {
case .known, .unreachable:
checking = false
term.start()
case .unknown(let info):
hostKeyRequest = HostKeyRequest(info: info, isChange: false)
case .changed(let info):
hostKeyRequest = HostKeyRequest(info: info, isChange: true)
}
}
}
}
}
}
func acceptHostKey() {
guard let info = hostKeyInfo else { return }
showingHostKey = false
if hostKeyChange {
func acceptHostKey(_ req: HostKeyRequest) {
hostKeyRequest = nil
if req.isChange {
_ = HostKeyService.revoke(host: profile.host, port: profile.port)
}
if HostKeyService.accept(info) {
if HostKeyService.accept(req.info) {
checking = false
term.note("Host-Key akzeptiert (\(info.keyType), \(info.fingerprintSHA256.prefix(19))…).")
term.note("Host-Key akzeptiert (\(req.info.keyType), \(req.info.fingerprintSHA256.prefix(19))…).")
term.start()
} else {
checking = false
term.fail("Host-Key konnte nicht in known_hosts gespeichert werden.")
}
hostKeyInfo = nil
}
func diagnose() {
@@ -1,5 +1,13 @@
import SwiftUI
/// Sheet-Request (Identifiable): .sheet(item:) rendert IMMER mit Wert —
/// ein `if let` im Sheet kann den Empty-Zweig nehmen und bleibt dann leer.
struct HostKeyRequest: Identifiable {
let id = UUID()
var info: HostKeyInfo
var isChange: Bool
}
/// Popup bei unbekanntem/geändertem Host-Key: Fingerprint prüfen, dann
/// akzeptieren (→ known_hosts + verbinden) oder abbrechen.
struct HostKeySheet: View {