mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
fix adding new hosts, it will navigate u to a new connection view with a host.blank, and add the host if it doesnt exist
added addhostifneeded extracted hostskeys stuff to hostkeysview added nav titles to everything removed tabs, now just a list renamed savedHosts -> hosts
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; };
|
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; };
|
||||||
A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */; };
|
A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */; };
|
||||||
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */; };
|
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */; };
|
||||||
|
A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819302E102D8700442D38 /* HostkeysView.swift */; };
|
||||||
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
||||||
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* SymbolPreview.swift */; };
|
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* SymbolPreview.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@@ -118,6 +119,7 @@
|
|||||||
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||||
A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManagerView.swift; sourceTree = "<group>"; };
|
A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManagerView.swift; sourceTree = "<group>"; };
|
||||||
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; };
|
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; };
|
||||||
|
A9D819302E102D8700442D38 /* HostkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostkeysView.swift; sourceTree = "<group>"; };
|
||||||
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
||||||
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolPreview.swift; sourceTree = "<group>"; };
|
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolPreview.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@@ -282,6 +284,7 @@
|
|||||||
children = (
|
children = (
|
||||||
A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */,
|
A96C6AFF2E0C45FE00F377FE /* KeyDetailView.swift */,
|
||||||
A98554542E05535F009051BD /* KeyManagerView.swift */,
|
A98554542E05535F009051BD /* KeyManagerView.swift */,
|
||||||
|
A9D819302E102D8700442D38 /* HostkeysView.swift */,
|
||||||
);
|
);
|
||||||
path = Keys;
|
path = Keys;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -497,6 +500,7 @@
|
|||||||
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */,
|
A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */,
|
||||||
A98554592E0553AA009051BD /* KeyManager.swift in Sources */,
|
A98554592E0553AA009051BD /* KeyManager.swift in Sources */,
|
||||||
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */,
|
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */,
|
||||||
|
A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */,
|
||||||
A98554552E05535F009051BD /* KeyManagerView.swift in Sources */,
|
A98554552E05535F009051BD /* KeyManagerView.swift in Sources */,
|
||||||
A923172D2E07138000ECE1E6 /* SSHTerminalDelegate.swift in Sources */,
|
A923172D2E07138000ECE1E6 /* SSHTerminalDelegate.swift in Sources */,
|
||||||
A96C6AFE2E0C43B600F377FE /* Keypair.swift in Sources */,
|
A96C6AFE2E0C43B600F377FE /* Keypair.swift in Sources */,
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ import SwiftUI
|
|||||||
class HostsManager: ObservableObject, @unchecked Sendable {
|
class HostsManager: ObservableObject, @unchecked Sendable {
|
||||||
private let userDefaults = NSUbiquitousKeyValueStore.default
|
private let userDefaults = NSUbiquitousKeyValueStore.default
|
||||||
|
|
||||||
@Published var savedHosts: [Host] = []
|
@Published var hosts: [Host] = []
|
||||||
@Published var themes: [Theme] = []
|
@Published var themes: [Theme] = []
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
loadSavedHosts()
|
loadHosts()
|
||||||
loadThemes()
|
loadThemes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? {
|
func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? {
|
||||||
if let index = savedHosts.firstIndex(where: { $0.id == hostSearchingFor.id }) {
|
if let index = hosts.firstIndex(where: { $0.id == hostSearchingFor.id }) {
|
||||||
return index
|
return index
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@@ -93,28 +93,28 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
|
|
||||||
func getHostMatching(_ HostSearchingFor: Host) -> Host? {
|
func getHostMatching(_ HostSearchingFor: Host) -> Host? {
|
||||||
guard let index = getHostIndexMatching(HostSearchingFor) else { return nil }
|
guard let index = getHostIndexMatching(HostSearchingFor) else { return nil }
|
||||||
return savedHosts[index]
|
return hosts[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateHost(_ updatedHost: Host) {
|
func updateHost(_ updatedHost: Host) {
|
||||||
let oldID = updatedHost.id
|
let oldID = updatedHost.id
|
||||||
|
|
||||||
if let index = savedHosts.firstIndex(where: { $0.id == updatedHost.id }) {
|
if let index = hosts.firstIndex(where: { $0.id == updatedHost.id }) {
|
||||||
var updateHostWithNewID = updatedHost
|
var updateHostWithNewID = updatedHost
|
||||||
updateHostWithNewID.id = UUID()
|
updateHostWithNewID.id = UUID()
|
||||||
withAnimation { savedHosts[index] = updateHostWithNewID }
|
withAnimation { hosts[index] = updateHostWithNewID }
|
||||||
|
|
||||||
updateHostWithNewID.id = oldID
|
updateHostWithNewID.id = oldID
|
||||||
withAnimation { savedHosts[index] = updateHostWithNewID }
|
withAnimation { hosts[index] = updateHostWithNewID }
|
||||||
saveSavedHosts()
|
saveHosts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplicateHost(_ hostToDup: Host) {
|
func duplicateHost(_ hostToDup: Host) {
|
||||||
var hostNewID = hostToDup
|
var hostNewID = hostToDup
|
||||||
hostNewID.id = UUID()
|
hostNewID.id = UUID()
|
||||||
if let index = savedHosts.firstIndex(where: { $0 == hostToDup }) {
|
if let index = hosts.firstIndex(where: { $0 == hostToDup }) {
|
||||||
savedHosts.insert(hostNewID, at: index+1)
|
hosts.insert(hostNewID, at: index+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,38 +131,44 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func moveHost(from: IndexSet, to: Int) {
|
func moveHost(from: IndexSet, to: Int) {
|
||||||
savedHosts.move(fromOffsets: from, toOffset: to)
|
hosts.move(fromOffsets: from, toOffset: to)
|
||||||
saveSavedHosts()
|
saveHosts()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSavedHosts() {
|
func loadHosts() {
|
||||||
userDefaults.synchronize()
|
userDefaults.synchronize()
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
guard let data = userDefaults.data(forKey: "savedHosts") else { return }
|
guard let data = userDefaults.data(forKey: "savedHosts") else { return }
|
||||||
|
|
||||||
if let decoded = try? decoder.decode([Host].self, from: data) {
|
if let decoded = try? decoder.decode([Host].self, from: data) {
|
||||||
self.savedHosts = decoded
|
self.hosts = decoded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveSavedHosts() {
|
func saveHosts() {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
if let encoded = try? encoder.encode(savedHosts) {
|
if let encoded = try? encoder.encode(hosts) {
|
||||||
userDefaults.set(encoded, forKey: "savedHosts")
|
userDefaults.set(encoded, forKey: "savedHosts")
|
||||||
userDefaults.synchronize()
|
userDefaults.synchronize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addHostIfNeeded(_ hostToAdd: Host) {
|
||||||
|
if !hosts.contains(hostToAdd) {
|
||||||
|
hosts.append(hostToAdd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func removeHost(_ host: Host) {
|
func removeHost(_ host: Host) {
|
||||||
if let index = savedHosts.firstIndex(where: { $0.id == host.id }) {
|
if let index = hosts.firstIndex(where: { $0.id == host.id }) {
|
||||||
let _ = withAnimation { savedHosts.remove(at: index) }
|
let _ = withAnimation { hosts.remove(at: index) }
|
||||||
saveSavedHosts()
|
saveHosts()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeys() -> [Keypair] {
|
func getKeys() -> [Keypair] {
|
||||||
var result: [Keypair] = []
|
var result: [Keypair] = []
|
||||||
for host in savedHosts {
|
for host in hosts {
|
||||||
let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey)
|
let keypair = Keypair(publicKey: host.publicKey, privateKey: host.privateKey)
|
||||||
if !result.contains(keypair) {
|
if !result.contains(keypair) {
|
||||||
result.append(keypair)
|
result.append(keypair)
|
||||||
@@ -174,7 +180,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
func getHostsKeysUsedOn(_ keys: [Keypair]) -> [Host] {
|
func getHostsKeysUsedOn(_ keys: [Keypair]) -> [Host] {
|
||||||
var result: [Host] = []
|
var result: [Host] = []
|
||||||
for key in keys {
|
for key in keys {
|
||||||
let hosts = savedHosts.filter({
|
let hosts = hosts.filter({
|
||||||
$0.publicKey == key.publicKey &&
|
$0.publicKey == key.publicKey &&
|
||||||
$0.privateKey == key.privateKey
|
$0.privateKey == key.privateKey
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct ShhShellApp: App {
|
|||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView(
|
ContentView(
|
||||||
handler: sshHandler,
|
handler: sshHandler,
|
||||||
hostsManger: hostsManager,
|
hostsManager: hostsManager,
|
||||||
keyManager: keyManager
|
keyManager: keyManager
|
||||||
)
|
)
|
||||||
.colorScheme(.dark)
|
.colorScheme(.dark)
|
||||||
|
|||||||
@@ -9,31 +9,38 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@ObservedObject var handler: SSHHandler
|
@ObservedObject var handler: SSHHandler
|
||||||
@ObservedObject var hostsManger: HostsManager
|
@ObservedObject var hostsManager: HostsManager
|
||||||
@ObservedObject var keyManager: KeyManager
|
@ObservedObject var keyManager: KeyManager
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TabView {
|
NavigationStack {
|
||||||
HostsView(
|
List {
|
||||||
handler: handler,
|
HostsView(
|
||||||
hostsManager: hostsManger,
|
handler: handler,
|
||||||
keyManager: keyManager
|
hostsManager: hostsManager,
|
||||||
)
|
keyManager: keyManager
|
||||||
.tabItem {
|
)
|
||||||
Label("Hosts", systemImage: "server.rack")
|
|
||||||
}
|
NavigationLink {
|
||||||
KeyManagerView(hostsManager: hostsManger, keyManager: keyManager)
|
KeyManagerView(hostsManager: hostsManager, keyManager: keyManager)
|
||||||
.tabItem {
|
} label: {
|
||||||
Label("Keys", systemImage: "key.2.on.ring")
|
Label("Keys", systemImage: "key.fill")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavigationLink {
|
||||||
|
HostkeysView(hostsManager: hostsManager)
|
||||||
|
} label: {
|
||||||
|
Label("Hostkey Fingerprints", systemImage: "lock.display")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ContentView(
|
ContentView(
|
||||||
handler: SSHHandler(host: Host.debug),
|
handler: SSHHandler(host: Host.debug),
|
||||||
hostsManger: HostsManager(),
|
hostsManager: HostsManager(),
|
||||||
keyManager: KeyManager()
|
keyManager: KeyManager()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ struct ConnectionView: View {
|
|||||||
shellView = ShellView(handler: handler)
|
shellView = ShellView(handler: handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onAppear {
|
||||||
|
hostsManager.addHostIfNeeded(handler.host)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,89 +12,76 @@ struct HostsView: View {
|
|||||||
@ObservedObject var hostsManager: HostsManager
|
@ObservedObject var hostsManager: HostsManager
|
||||||
@ObservedObject var keyManager: KeyManager
|
@ObservedObject var keyManager: KeyManager
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
if hostsManager.hosts.isEmpty {
|
||||||
List {
|
Text("Add your first Host!")
|
||||||
if hostsManager.savedHosts.isEmpty {
|
}
|
||||||
Text("Add your first Host!")
|
|
||||||
Button() {
|
|
||||||
withAnimation { hostsManager.savedHosts.append(Host.blank) }
|
|
||||||
} label: {
|
|
||||||
Text("Create")
|
|
||||||
}
|
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
}
|
|
||||||
|
|
||||||
//proves that u can connect to multiple at the same time
|
//proves that u can connect to multiple at the same time
|
||||||
NavigationLink() {
|
NavigationLink() {
|
||||||
ForEach(hostsManager.savedHosts) { host in
|
ForEach(hostsManager.hosts) { host in
|
||||||
let miniHandler = SSHHandler(host: host)
|
let miniHandler = SSHHandler(host: host)
|
||||||
TerminalController(handler: miniHandler)
|
TerminalController(handler: miniHandler)
|
||||||
.onAppear { miniHandler.go() }
|
.onAppear { miniHandler.go() }
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Label("multiview", systemImage: "square.split.2x2")
|
|
||||||
}
|
|
||||||
|
|
||||||
ForEach(hostsManager.savedHosts) { host in
|
|
||||||
NavigationLink() {
|
|
||||||
ConnectionView(
|
|
||||||
handler: SSHHandler(host: host),
|
|
||||||
hostsManager: hostsManager,
|
|
||||||
keyManager: keyManager
|
|
||||||
)
|
|
||||||
} label: {
|
|
||||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
|
||||||
.frame(width: 40, height: 40)
|
|
||||||
Text(hostsManager.makeLabel(forHost: host))
|
|
||||||
}
|
|
||||||
.id(host)
|
|
||||||
.animation(.default, value: host)
|
|
||||||
.swipeActions(edge: .trailing) {
|
|
||||||
Button(role: .destructive) {
|
|
||||||
hostsManager.removeHost(host)
|
|
||||||
} label: {
|
|
||||||
Label("Delete", systemImage: "trash")
|
|
||||||
}
|
|
||||||
Button() {
|
|
||||||
hostsManager.duplicateHost(host)
|
|
||||||
} label: {
|
|
||||||
Label("Duplicate", systemImage: "square.filled.on.square")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onMove(perform: {
|
|
||||||
hostsManager.moveHost(from: $0, to: $1)
|
|
||||||
})
|
|
||||||
|
|
||||||
Section() {
|
|
||||||
NavigationLink {
|
|
||||||
ThemeManagerView(hostsManager: hostsManager)
|
|
||||||
} label: {
|
|
||||||
Label("Themes", systemImage: "swatchpalette")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.transition(.opacity)
|
} label: {
|
||||||
.toolbar {
|
Label("multiview", systemImage: "square.split.2x2")
|
||||||
ToolbarItem(placement: .confirmationAction) {
|
}
|
||||||
let host = Host.blank
|
|
||||||
NavigationLink {
|
ForEach(hostsManager.hosts) { host in
|
||||||
ConnectionView(
|
NavigationLink() {
|
||||||
handler: SSHHandler(host: host),
|
ConnectionView(
|
||||||
hostsManager: hostsManager,
|
handler: SSHHandler(host: host),
|
||||||
keyManager: keyManager
|
hostsManager: hostsManager,
|
||||||
)
|
keyManager: keyManager
|
||||||
.onAppear {
|
)
|
||||||
withAnimation { hostsManager.savedHosts.append(host) }
|
} label: {
|
||||||
}
|
SymbolPreview(symbol: host.symbol, label: host.label)
|
||||||
} label: {
|
.frame(width: 40, height: 40)
|
||||||
Label("Add", systemImage: "plus")
|
Text(hostsManager.makeLabel(forHost: host))
|
||||||
}
|
}
|
||||||
|
.id(host)
|
||||||
|
.animation(.default, value: host)
|
||||||
|
.swipeActions(edge: .trailing) {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
hostsManager.removeHost(host)
|
||||||
|
} label: {
|
||||||
|
Label("Delete", systemImage: "trash")
|
||||||
|
}
|
||||||
|
Button() {
|
||||||
|
hostsManager.duplicateHost(host)
|
||||||
|
} label: {
|
||||||
|
Label("Duplicate", systemImage: "square.filled.on.square")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
.onMove(perform: {
|
||||||
|
hostsManager.moveHost(from: $0, to: $1)
|
||||||
|
})
|
||||||
|
|
||||||
|
Section() {
|
||||||
|
NavigationLink {
|
||||||
|
ThemeManagerView(hostsManager: hostsManager)
|
||||||
|
} label: {
|
||||||
|
Label("Themes", systemImage: "swatchpalette")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.transition(.opacity)
|
||||||
|
.navigationTitle("ShhShell")
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
|
NavigationLink {
|
||||||
|
ConnectionView(
|
||||||
|
handler: SSHHandler(host: Host.blank),
|
||||||
|
hostsManager: hostsManager,
|
||||||
|
keyManager: keyManager
|
||||||
|
)
|
||||||
|
} label: {
|
||||||
|
Label("Add", systemImage: "plus")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
58
ShhShell/Views/Keys/HostkeysView.swift
Normal file
58
ShhShell/Views/Keys/HostkeysView.swift
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// HostkeysView.swift
|
||||||
|
// ShhShell
|
||||||
|
//
|
||||||
|
// Created by neon443 on 28/06/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct HostkeysView: View {
|
||||||
|
@ObservedObject var hostsManager: HostsManager
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationStack {
|
||||||
|
List {
|
||||||
|
if hostsManager.hosts.isEmpty {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Looking empty 'round here...")
|
||||||
|
.font(.title3)
|
||||||
|
.bold()
|
||||||
|
.padding(.bottom)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Connect to some hosts to collect more hostkeys!")
|
||||||
|
.padding(.bottom)
|
||||||
|
Text("ShhShell remembers hostkey fingerprints for you, and can alert you if they change.")
|
||||||
|
.font(.subheadline)
|
||||||
|
Text("This could be due a man in the middle attack, where a bad actor tries to impersonate your server.")
|
||||||
|
.font(.subheadline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEach(hostsManager.hosts) { host in
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
if !host.name.isEmpty {
|
||||||
|
Text("name")
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
.font(.caption)
|
||||||
|
Text(host.name)
|
||||||
|
.bold()
|
||||||
|
}
|
||||||
|
Text("address")
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
.font(.caption)
|
||||||
|
Text(host.address)
|
||||||
|
.bold()
|
||||||
|
Text(host.key ?? "nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle("Hostkeys")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
HostkeysView(hostsManager: HostsManager())
|
||||||
|
}
|
||||||
@@ -25,45 +25,7 @@ struct KeyManagerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Section {
|
|
||||||
NavigationLink {
|
|
||||||
List {
|
|
||||||
if hostsManager.savedHosts.isEmpty {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text("Looking empty 'round here...")
|
|
||||||
.font(.title3)
|
|
||||||
.bold()
|
|
||||||
.padding(.bottom)
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
Text("Connect to some hosts to collect more hostkeys!")
|
|
||||||
.padding(.bottom)
|
|
||||||
Text("ShhShell remembers hostkey fingerprints for you, and can alert you if they change.")
|
|
||||||
.font(.subheadline)
|
|
||||||
Text("This could be due a man in the middle attack, where a bad actor tries to impersonate your server.")
|
|
||||||
.font(.subheadline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ForEach(hostsManager.savedHosts) { host in
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if !host.name.isEmpty {
|
|
||||||
Text(host.name)
|
|
||||||
.bold()
|
|
||||||
}
|
|
||||||
Text(host.address)
|
|
||||||
.bold()
|
|
||||||
Text(host.key ?? "nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
HStack {
|
|
||||||
Image(systemName: "server.rack")
|
|
||||||
Image(systemName: "key.fill")
|
|
||||||
Text("Hostkey fingerprints")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Button("ed25519") {
|
Button("ed25519") {
|
||||||
keyManager.generateEd25519()
|
keyManager.generateEd25519()
|
||||||
}
|
}
|
||||||
@@ -75,6 +37,7 @@ struct KeyManagerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.navigationTitle("Keys")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ struct ThemeManagerView: View {
|
|||||||
}
|
}
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.scrollIndicators(.hidden)
|
.scrollIndicators(.hidden)
|
||||||
|
.navigationTitle("Themes")
|
||||||
.alert("Enter URL", isPresented: $showAlert) {
|
.alert("Enter URL", isPresented: $showAlert) {
|
||||||
TextField("", text: $importURL, prompt: Text("URL"))
|
TextField("", text: $importURL, prompt: Text("URL"))
|
||||||
Button() {
|
Button() {
|
||||||
|
|||||||
Reference in New Issue
Block a user