5e77731da0
ci / rust (push) Has been cancelled
The app grows from a dev connect form into a real client shell: - Home is a grid of saved hosts (UserDefaults-persisted; context menu: Remove / Forget Identity), "+" in the toolbar opens the add-host sheet, the stream mode moved into Settings (⌘, / gear) — native resolution stays the only mode, no scaling. - Trust is now explicit: the protocol always supported certificate pinning, but the app passed no pin and discarded the observed fingerprint — silently trusting any host. First connect now shows the host's SHA-256 fingerprint (compare with the "clients pin this fingerprint" line in the host log) over the live-but-blurred stream; the stream must pump immediately (the opening IDR is the only guaranteed one), so StreamView gains a capturesCursor switch to keep the cursor free while the prompt needs clicking, and input capture starts only after confirmation. Trusting pins the fingerprint per host; a changed host identity then refuses to connect. - PUNKTFUNK_AUTOCONNECT keeps working (auto-trusts, doesn't touch the saved hosts). Host→client authorization (pairing PIN) remains a punktfunk-core roadmap item — the host still accepts any client that can reach its port. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.5 KiB
Swift
43 lines
1.5 KiB
Swift
// "+" sheet: name (optional) + address + port → a card in the hosts grid. The first
|
|
// actual connection runs the trust-on-first-use fingerprint prompt.
|
|
|
|
import SwiftUI
|
|
|
|
struct AddHostSheet: View {
|
|
@Environment(\.dismiss) private var dismiss
|
|
@State private var name = ""
|
|
@State private var address = ""
|
|
@State private var port = 9777
|
|
|
|
let onAdd: (StoredHost) -> Void
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0) {
|
|
Form {
|
|
TextField("Name", text: $name, prompt: Text("Optional — e.g. Living Room"))
|
|
TextField("Address", text: $address, prompt: Text("IP or hostname"))
|
|
TextField("Port", value: $port, format: .number.grouping(.never))
|
|
}
|
|
.formStyle(.grouped)
|
|
HStack {
|
|
Button("Cancel", role: .cancel) { dismiss() }
|
|
.keyboardShortcut(.cancelAction)
|
|
Spacer()
|
|
Button("Add Host") {
|
|
onAdd(StoredHost(
|
|
name: name.trimmingCharacters(in: .whitespaces),
|
|
address: address.trimmingCharacters(in: .whitespaces),
|
|
port: UInt16(clamping: port)))
|
|
dismiss()
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
.keyboardShortcut(.defaultAction)
|
|
.disabled(address.trimmingCharacters(in: .whitespaces).isEmpty)
|
|
}
|
|
.padding(16)
|
|
}
|
|
.frame(width: 380)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
}
|
|
}
|