From 7ceef899df1c2cbac50ac6d3adab67ec79a82c45 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:59:59 +0100 Subject: [PATCH] fix duplicate ssh keys in keys, now shows the hosts that use that key if u tap on it added theme deletion added animations on change of themes list getkeys doesnt return duplicates, thanks to: wrote a custom == operator to check if keys are the same, ignoring uuid added gethostskeysusedon to get the hosts that use a key fix refreshing of hosts on modification added cancel to import alert --- ShhShell/Host/HostsManager.swift | 26 +++++++++++++++++--- ShhShell/Keys/Keypair.swift | 9 +++++++ ShhShell/Views/Hosts/HostsView.swift | 1 + ShhShell/Views/Keys/KeyDetailView.swift | 11 +++++++++ ShhShell/Views/Themes/ThemeManagerView.swift | 4 ++- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/ShhShell/Host/HostsManager.swift b/ShhShell/Host/HostsManager.swift index bdb3770..2b84207 100644 --- a/ShhShell/Host/HostsManager.swift +++ b/ShhShell/Host/HostsManager.swift @@ -50,6 +50,7 @@ class HostsManager: ObservableObject, @unchecked Sendable { func renameTheme(_ theme: Theme?, to newName: String) { guard let theme else { return } + guard theme.name != newName else { return } guard let index = themes.firstIndex(where: {$0.id == theme.id}) else { return } var newTheme = themes[index] newTheme.name = newName @@ -58,6 +59,12 @@ class HostsManager: ObservableObject, @unchecked Sendable { saveThemes() } + func deleteTheme(_ themeToDel: Theme) { + guard let index = themes.firstIndex(where: {$0 == themeToDel}) else { return } + themes.remove(at: index) + saveThemes() + } + @MainActor func importTheme(name: String, data: Data?) { guard let data else { return } @@ -156,15 +163,26 @@ class HostsManager: ObservableObject, @unchecked Sendable { func getKeys() -> [Keypair] { var result: [Keypair] = [] for host in savedHosts { - if result.contains(where: { $0 == Keypair(publicKey: host.publicKey, privateKey: host.privateKey)}) { - - } else { - result.append(Keypair(publicKey: host.publicKey, privateKey: host.privateKey)) + let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey) + if !result.contains(keypair) { + result.append(keypair) } } return result } + func getHostsKeysUsedOn(_ keys: [Keypair]) -> [Host] { + var result: [Host] = [] + for key in keys { + let hosts = savedHosts.filter({ + $0.publicKey == key.publicKey && + $0.privateKey == key.privateKey + }) + result += hosts + } + return result + } + func authWithBiometrics() async -> Bool { let context = LAContext() var error: NSError? diff --git a/ShhShell/Keys/Keypair.swift b/ShhShell/Keys/Keypair.swift index a9b1c36..eca81ba 100644 --- a/ShhShell/Keys/Keypair.swift +++ b/ShhShell/Keys/Keypair.swift @@ -24,4 +24,13 @@ struct Keypair: KeypairProtocol { self.publicKey = publicKey self.privateKey = privateKey } + + static func ==(lhs: Keypair, rhs: Keypair) -> Bool { + if lhs.publicKey?.base64EncodedString() == rhs.publicKey?.base64EncodedString() + && lhs.privateKey?.base64EncodedString() == rhs.privateKey?.base64EncodedString() { + return true + } else { + return false + } + } } diff --git a/ShhShell/Views/Hosts/HostsView.swift b/ShhShell/Views/Hosts/HostsView.swift index a53113c..d0163ce 100644 --- a/ShhShell/Views/Hosts/HostsView.swift +++ b/ShhShell/Views/Hosts/HostsView.swift @@ -48,6 +48,7 @@ struct HostsView: View { .frame(width: 40, height: 40) Text(hostsManager.makeLabel(forHost: host)) } + .id(host) .animation(.default, value: host) .swipeActions(edge: .trailing) { Button(role: .destructive) { diff --git a/ShhShell/Views/Keys/KeyDetailView.swift b/ShhShell/Views/Keys/KeyDetailView.swift index 0f43342..cfeeedb 100644 --- a/ShhShell/Views/Keys/KeyDetailView.swift +++ b/ShhShell/Views/Keys/KeyDetailView.swift @@ -14,6 +14,17 @@ struct KeyDetailView: View { var body: some View { List { + VStack(alignment: .leading) { + Text("Used on") + .bold() + ForEach(hostsManager.getHostsKeysUsedOn([keypair])) { host in + HStack { + SymbolPreview(symbol: host.symbol, label: host.label) + .frame(width: 40, height: 40) + Text(hostsManager.makeLabel(forHost: host)) + } + } + } VStack(alignment: .leading) { Text("Public key") .bold() diff --git a/ShhShell/Views/Themes/ThemeManagerView.swift b/ShhShell/Views/Themes/ThemeManagerView.swift index 53033a2..58feb94 100644 --- a/ShhShell/Views/Themes/ThemeManagerView.swift +++ b/ShhShell/Views/Themes/ThemeManagerView.swift @@ -40,13 +40,14 @@ struct ThemeManagerView: View { Label("Rename", systemImage: "pencil") } Button(role: .destructive) { - + hostsManager.deleteTheme(theme) } label: { Label("Delete", systemImage: "trash") } } } } + .animation(.default, value: hostsManager.themes) .alert("", isPresented: $showRenameAlert) { TextField("", text: $rename) Button("OK") { @@ -66,6 +67,7 @@ struct ThemeManagerView: View { } label: { Label("Import", systemImage: "square.and.arrow.down") } + Button("Cancel") {} } .toolbar { ToolbarItem() {