From 7adc2b7059212974a009536ce48d7c6c92b002fe Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Fri, 6 Jun 2025 21:14:11 +0100 Subject: [PATCH] UI with custom host, username and pw not hardcoded anymore set host port username and pw currently only password auth lol can get hostkeys replaced lots of fatalerrors with false returns --- ShhShell/SSHHandler.swift | 162 +++++++++++++++++++++---------- ShhShell/ShhShellApp.swift | 4 +- ShhShell/Views/ContentView.swift | 36 +++++-- 3 files changed, 141 insertions(+), 61 deletions(-) diff --git a/ShhShell/SSHHandler.swift b/ShhShell/SSHHandler.swift index 662bb84..4963f14 100644 --- a/ShhShell/SSHHandler.swift +++ b/ShhShell/SSHHandler.swift @@ -11,24 +11,58 @@ import OSLog class SSHHandler: ObservableObject { var session: ssh_session? + + @Published var username: String + @Published var password: String + @Published var address: String + @Published var port: Int private let logger = Logger(subsystem: "xy", category: "sshHandler") - init() { -// session = ssh_new() -// guard session != nil else { return } + init( + username: String = "", + password: String = "", + address: String = "", + port: Int = 22 + ) { + #if DEBUG + self.username = "root" + self.password = "root" + self.address = "localhost" + self.port = 2222 + #endif + self.username = username + self.password = password + self.address = address + self.port = port } - - func connect() { + + func getHostkey() { + 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)) + } + } + } + + func connect() -> Bool { + defer { + getHostkey() + getAuthMethods() + } + var verbosity: Int = 0 - var port: Int = 2222 - + session = ssh_new() guard session != nil else { - fatalError("no ssh session??!?!") + return false } - ssh_options_set(session, SSH_OPTIONS_HOST, "localhost") + ssh_options_set(session, SSH_OPTIONS_HOST, address) ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) ssh_options_set(session, SSH_OPTIONS_PORT, &port) @@ -36,49 +70,42 @@ class SSHHandler: ObservableObject { if status != SSH_OK { logger.critical("connection not ok: \(status)") logSshGetError() - fatalError() + return false } + return true } func disconnect() { - guard session != nil else { fatalError("no ssession") } + guard session != nil else { + print("cant disconnect when im not connected") + return + } ssh_disconnect(session) + ssh_free(session) } - func hardcodedAuth() { - var hostkey: ssh_key? - ssh_get_server_publickey(session, &hostkey) - if let hostkey = hostkey { - print("hostkey \(hostkey)") + func testExec() -> Bool { + if ssh_is_connected(session) == 0 { + if !connect() { + return false + } } - - let password = "root" - - let rc = ssh_userauth_password(session, "root", password) - if rc != SSH_AUTH_SUCCESS.rawValue { - print("auth failure") - } - } - - func testExec() { - connect() - defer { disconnect();ssh_free(session) } - - hardcodedAuth() + + guard authWithPw() else { return false } var status: CInt var buffer: [Int] = Array(repeating: 0, count: 256) var nbytes: CInt let channel = ssh_channel_new(session) - guard channel != nil else { fatalError("noChannel") } + guard channel != nil else { return false } status = ssh_channel_open_session(channel) guard status == SSH_OK else { ssh_channel_free(channel) logger.critical("session opening error") logSshGetError() - return + return false } status = ssh_channel_request_exec(channel, "uptime") @@ -87,7 +114,7 @@ class SSHHandler: ObservableObject { ssh_channel_free(channel) logger.critical("session opening error") logSshGetError() - return + return false } nbytes = ssh_channel_read( @@ -103,7 +130,7 @@ class SSHHandler: ObservableObject { ssh_channel_free(channel) logger.critical("write error") logSshGetError() - return + return false } nbytes = ssh_channel_read(channel, &buffer, UInt32(MemoryLayout.size(ofValue: Character.self)), 0) } @@ -113,44 +140,56 @@ class SSHHandler: ObservableObject { ssh_channel_free(channel) logger.critical("didnt read?") logSshGetError() - return + return false } ssh_channel_send_eof(channel) ssh_channel_close(channel) ssh_channel_free(channel) print("testExec succeeded") + return true } - func authWithPubkey() { + func authWithPubkey() -> Bool { var status: CInt status = ssh_userauth_publickey_auto(session, nil, nil) if status == SSH_AUTH_ERROR.rawValue { print("pubkey auth failed") logSshGetError() - fatalError() + return false } + return true } - func authWithPw(_ username: String, _ password: String) { + func authWithPw() -> Bool { var status: CInt status = ssh_userauth_password(session, username, password) - guard status != SSH_ERROR else { + guard status != SSH_AUTH_SUCCESS.rawValue else { print("ssh pw auth error") logSshGetError() - return + return false } + print("auth success") + return true } - func authWithKbInt() { + func authWithKbInt() -> Bool { var status: CInt status = ssh_userauth_kbdint(session, nil, nil) while status == SSH_AUTH_INFO.rawValue { let name, instruction: String var nprompts: CInt - name = UnsafeRawPointer(String(ssh_userauth_kbdint_getname(session))) - instruction = String(ssh_userauth_kbdint_getinstruction(session)) + if let namePtr = ssh_userauth_kbdint_getname(session) { + name = String(cString: namePtr) + } else { + return false + } + if let instrPtr = ssh_userauth_kbdint_getinstruction(session) { + instruction = String(cString: instrPtr) + } else { + return false + } nprompts = ssh_userauth_kbdint_getnprompts(session) if name.count > 0 { @@ -161,28 +200,47 @@ class SSHHandler: ObservableObject { } for promptI in 0.. - var echo: CChar + var echo: CChar = 0 prompt = ssh_userauth_kbdint_getprompt(session, UInt32(promptI), &echo) if echo != 0 { var buffer: [CChar] = Array(repeating: 0, count: 128) - var ptr: UnsafeMutablePointer = .init(mutating: buffer) + let ptr: UnsafeMutablePointer = .init(mutating: buffer) print(prompt) if fgets(&buffer, Int32(MemoryLayout.size(ofValue: buffer)), stdin) == nil { - fatalError("autherror") + return false } - if (ptr = strchr(buffer, 0)) != nil { - ptr.pointee = "\0" - } - if ssh_userauth_kbdint_setanswer(session, promptI, buffer) < 0 { - fatalError("autherr") + ptr.pointee = 0//prob fucked + if ssh_userauth_kbdint_setanswer(session, UInt32(promptI), buffer) < 0 { + return false } memset(&buffer, 0, buffer.count) + } else { + if (ssh_userauth_kbdint_setanswer(session, UInt32(promptI), &password) != 0) { + return false + } } } + status = ssh_userauth_kbdint(session, nil, nil) + } + return true + } + + func authWithNone() -> Bool { + let status = ssh_userauth_none(session, nil) + if status == SSH_AUTH_SUCCESS.rawValue { + print("no security moment lol") + return true + } else { + return false } } + func getAuthMethods() { + var method: CInt + method = ssh_userauth_list(session, username) + } + func logSshGetError() { - logger.critical("\(String(describing: ssh_get_error(&self.session)))") + logger.critical("\(String(cString: ssh_get_error(&self.session)))") } } diff --git a/ShhShell/ShhShellApp.swift b/ShhShell/ShhShellApp.swift index be601cc..33c0c61 100644 --- a/ShhShell/ShhShellApp.swift +++ b/ShhShell/ShhShellApp.swift @@ -9,9 +9,11 @@ import SwiftUI @main struct ShhShellApp: App { + @StateObject var sshHandler: SSHHandler = SSHHandler(username: "", password: "") + var body: some Scene { WindowGroup { - ContentView() + ContentView(handler: sshHandler) } .windowResizability(.contentMinSize) } diff --git a/ShhShell/Views/ContentView.swift b/ShhShell/Views/ContentView.swift index 10f6992..6f23d7e 100644 --- a/ShhShell/Views/ContentView.swift +++ b/ShhShell/Views/ContentView.swift @@ -8,21 +8,41 @@ import SwiftUI struct ContentView: View { - var sshHandler = SSHHandler() + @ObservedObject var handler: SSHHandler var body: some View { VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - Button("go") { - sshHandler.testExec() + TextField("address", text: $handler.address) + .textFieldStyle(.roundedBorder) + TextField( + "port", + text: Binding( + get: { String(handler.port) }, + set: { handler.port = Int($0) ?? 22} ) + ) + .keyboardType(.numberPad) + .textFieldStyle(.roundedBorder) + TextField("username", text: $handler.username) + .textFieldStyle(.roundedBorder) + TextField("password", text: $handler.password) + .textFieldStyle(.roundedBorder) + + Button("connect & auth") { + handler.connect() + handler.authWithPw() + } + Button("disconnect & free") { + handler.disconnect() + } + Button("testExec") { + handler.testExec() } } } } #Preview { - ContentView() + ContentView( + handler: SSHHandler(username: "root", password: "root") + ) }