diff --git a/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json index 2305880..8b7e047 100644 --- a/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,6 +1,7 @@ { "images" : [ { + "filename" : "ShhShell.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/Resources/Assets.xcassets/AppIcon.appiconset/ShhShell.png b/Resources/Assets.xcassets/AppIcon.appiconset/ShhShell.png new file mode 100644 index 0000000..f7c9ac0 Binary files /dev/null and b/Resources/Assets.xcassets/AppIcon.appiconset/ShhShell.png differ diff --git a/ShhShell.pxd b/ShhShell.pxd new file mode 100644 index 0000000..ede140f Binary files /dev/null and b/ShhShell.pxd differ diff --git a/ShhShell/SSHHandler.swift b/ShhShell/SSHHandler.swift index 51a0f86..a99a5df 100644 --- a/ShhShell/SSHHandler.swift +++ b/ShhShell/SSHHandler.swift @@ -10,13 +10,15 @@ import LibSSH import OSLog class SSHHandler: ObservableObject { - var session: ssh_session? + private var session: ssh_session? @Published var authorized: Bool = false @Published var username: String @Published var password: String @Published var address: String @Published var port: Int + + @Published var hostkey: Data? private let logger = Logger(subsystem: "xy", category: "sshHandler") @@ -38,22 +40,23 @@ class SSHHandler: ObservableObject { #endif } - func getHostkey() { + func getHostkey() -> Data? { var hostkey: ssh_key? ssh_get_server_publickey(session, &hostkey) var hostkeyB64: UnsafeMutablePointer? = nil - if ssh_pki_export_pubkey_base64(hostkey, &hostkeyB64) == SSH_OK { - if let hostkeyB64 = hostkeyB64 { - print(String(cString: hostkeyB64)) - } - } + + let status = ssh_pki_export_pubkey_base64(hostkey, &hostkeyB64) + guard status == SSH_OK else { return nil } + guard let data = hostkeyB64 else { return nil } + + return Data(base64Encoded: String(cString: data)) } func connect() -> Bool { defer { getAuthMethods() - getHostkey() + self.hostkey = getHostkey() } var verbosity: Int = 0 @@ -85,6 +88,7 @@ class SSHHandler: ObservableObject { ssh_free(session) session = nil authorized = false + hostkey = nil } func testExec() -> Bool { @@ -262,7 +266,7 @@ class SSHHandler: ObservableObject { ssh_channel_free(channel) } - func interactiveShellSession(channel: ssh_channel) { + private func interactiveShellSession(channel: ssh_channel) { var status: CInt status = ssh_channel_request_pty(channel) diff --git a/ShhShell/Views/ContentView.swift b/ShhShell/Views/ContentView.swift index 6ef8ebc..a0ff550 100644 --- a/ShhShell/Views/ContentView.swift +++ b/ShhShell/Views/ContentView.swift @@ -10,19 +10,28 @@ import SwiftUI struct ContentView: View { @ObservedObject var handler: SSHHandler @State var connected: Bool = false - @State var testSucceded: Bool = false + @State var testSucceded: Bool? var body: some View { VStack { Text(connected ? "connected" : "not connected") .foregroundStyle(connected ? .green : .red) + Text(handler.authorized ? "authorized" : "unauthorized") .foregroundStyle(handler.authorized ? .green : .red) - if testSucceded { - Image(systemName: "checkmark.circle") + + if let testSucceded = testSucceded { + Image(systemName: testSucceded ? "checkmark.circle" : "xmark.circle") + .foregroundStyle(testSucceded ? .green : .red) } + + if handler.hostkey != nil { + Text("Hostkey: \(handler.hostkey!.base64EncodedString())") + } + TextField("address", text: $handler.address) .textFieldStyle(.roundedBorder) + TextField( "port", text: Binding( @@ -31,8 +40,10 @@ struct ContentView: View { ) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) + TextField("username", text: $handler.username) .textFieldStyle(.roundedBorder) + TextField("password", text: $handler.password) .textFieldStyle(.roundedBorder) @@ -42,20 +53,28 @@ struct ContentView: View { } handler.authWithPw() } + .disabled(connected) + Button("disconnect") { handler.disconnect() withAnimation { testSucceded = false } - withAnimation { connected = false} + withAnimation { connected = false } + withAnimation { testSucceded = nil } } + .disabled(!connected) + Button("run a test command") { - withAnimation { - if handler.testExec() { - testSucceded = true - } else { - testSucceded = false - } + if handler.testExec() { + withAnimation { testSucceded = true } + } else { + withAnimation { testSucceded = false } } } + .disabled(!(connected && handler.authorized)) + + Button("request a shell") { + handler.openShell() + } } } }