mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
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
This commit is contained in:
@@ -50,6 +50,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
|
|
||||||
func renameTheme(_ theme: Theme?, to newName: String) {
|
func renameTheme(_ theme: Theme?, to newName: String) {
|
||||||
guard let theme else { return }
|
guard let theme else { return }
|
||||||
|
guard theme.name != newName else { return }
|
||||||
guard let index = themes.firstIndex(where: {$0.id == theme.id}) else { return }
|
guard let index = themes.firstIndex(where: {$0.id == theme.id}) else { return }
|
||||||
var newTheme = themes[index]
|
var newTheme = themes[index]
|
||||||
newTheme.name = newName
|
newTheme.name = newName
|
||||||
@@ -58,6 +59,12 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
saveThemes()
|
saveThemes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteTheme(_ themeToDel: Theme) {
|
||||||
|
guard let index = themes.firstIndex(where: {$0 == themeToDel}) else { return }
|
||||||
|
themes.remove(at: index)
|
||||||
|
saveThemes()
|
||||||
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
func importTheme(name: String, data: Data?) {
|
func importTheme(name: String, data: Data?) {
|
||||||
guard let data else { return }
|
guard let data else { return }
|
||||||
@@ -156,15 +163,26 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
func getKeys() -> [Keypair] {
|
func getKeys() -> [Keypair] {
|
||||||
var result: [Keypair] = []
|
var result: [Keypair] = []
|
||||||
for host in savedHosts {
|
for host in savedHosts {
|
||||||
if result.contains(where: { $0 == Keypair(publicKey: host.publicKey, privateKey: host.privateKey)}) {
|
let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey)
|
||||||
|
if !result.contains(keypair) {
|
||||||
} else {
|
result.append(keypair)
|
||||||
result.append(Keypair(publicKey: host.publicKey, privateKey: host.privateKey))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
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 {
|
func authWithBiometrics() async -> Bool {
|
||||||
let context = LAContext()
|
let context = LAContext()
|
||||||
var error: NSError?
|
var error: NSError?
|
||||||
|
|||||||
@@ -24,4 +24,13 @@ struct Keypair: KeypairProtocol {
|
|||||||
self.publicKey = publicKey
|
self.publicKey = publicKey
|
||||||
self.privateKey = privateKey
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ struct HostsView: View {
|
|||||||
.frame(width: 40, height: 40)
|
.frame(width: 40, height: 40)
|
||||||
Text(hostsManager.makeLabel(forHost: host))
|
Text(hostsManager.makeLabel(forHost: host))
|
||||||
}
|
}
|
||||||
|
.id(host)
|
||||||
.animation(.default, value: host)
|
.animation(.default, value: host)
|
||||||
.swipeActions(edge: .trailing) {
|
.swipeActions(edge: .trailing) {
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ struct KeyDetailView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
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) {
|
VStack(alignment: .leading) {
|
||||||
Text("Public key")
|
Text("Public key")
|
||||||
.bold()
|
.bold()
|
||||||
|
|||||||
@@ -40,13 +40,14 @@ struct ThemeManagerView: View {
|
|||||||
Label("Rename", systemImage: "pencil")
|
Label("Rename", systemImage: "pencil")
|
||||||
}
|
}
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
|
hostsManager.deleteTheme(theme)
|
||||||
} label: {
|
} label: {
|
||||||
Label("Delete", systemImage: "trash")
|
Label("Delete", systemImage: "trash")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.animation(.default, value: hostsManager.themes)
|
||||||
.alert("", isPresented: $showRenameAlert) {
|
.alert("", isPresented: $showRenameAlert) {
|
||||||
TextField("", text: $rename)
|
TextField("", text: $rename)
|
||||||
Button("OK") {
|
Button("OK") {
|
||||||
@@ -66,6 +67,7 @@ struct ThemeManagerView: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Label("Import", systemImage: "square.and.arrow.down")
|
Label("Import", systemImage: "square.and.arrow.down")
|
||||||
}
|
}
|
||||||
|
Button("Cancel") {}
|
||||||
}
|
}
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem() {
|
ToolbarItem() {
|
||||||
|
|||||||
Reference in New Issue
Block a user