From db36c56f292ff9e59b47659a099538dbd07da3f3 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Wed, 25 Jun 2025 11:40:25 +0100 Subject: [PATCH] improved disconnection - will dismiss terminal on `exit` -- before you had to type more to exit improved connection logic with a try catch improved disconnection doesnt crash fix [int] to [cchar] reduced mem usage code cleanup try? -> catch print(error.localizedDesc) guard let var = var else ---> guard let var else removed file importers as it didnt eork compbined guards in writetochannel --- ShhShell/SSH/SSHHandler.swift | 65 ++++++++++++------- ShhShell/Views/ConnectionView.swift | 43 ------------ ShhShell/Views/Terminal/SSHTerminalView.swift | 4 +- 3 files changed, 45 insertions(+), 67 deletions(-) diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 2149cd0..1b5b3a5 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -58,13 +58,18 @@ class SSHHandler: @unchecked Sendable, ObservableObject { return } - guard let _ = try? connect() else { return } - + do { + try connect() + } catch { + print("error in connect \(error.localizedDescription)") + } + guard connected else { return } if !host.password.isEmpty { do { try authWithPw() } catch { print("pw auth error") + print(error.localizedDescription) } } else { do { @@ -74,6 +79,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject { } } catch { print("error with pubkey auth") + print(error.localizedDescription) } } openShell() @@ -121,7 +127,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject { withAnimation { testSuceeded = nil } } - ssh_channel_send_eof(self.channel) + //send eof if open + if ssh_channel_is_open(channel) == 1 { + ssh_channel_send_eof(channel) + } ssh_channel_free(self.channel) self.channel = nil @@ -157,7 +166,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject { } var status: CInt - var buffer: [Int] = Array(repeating: 0, count: 256) + var buffer: [CChar] = Array(repeating: 0, count: 256) var nbytes: CInt let channel = ssh_channel_new(session) @@ -236,8 +245,13 @@ class SSHHandler: @unchecked Sendable, ObservableObject { fileManager.createFile(atPath: tempPubkey.path(), contents: nil) fileManager.createFile(atPath: tempKey.path(), contents: nil) - try? pubInp.write(to: tempPubkey, options: .completeFileProtection) - try? privInp.write(to: tempKey, options: .completeFileProtection) + do { + try pubInp.write(to: tempPubkey, options: .completeFileProtection) + try privInp.write(to: tempKey, options: .completeFileProtection) + } catch { + print("file writing error") + print(error.localizedDescription) + } let attributes: [FileAttributeKey: Any] = [.posixPermissions: 0o600] do { @@ -271,8 +285,13 @@ class SSHHandler: @unchecked Sendable, ObservableObject { ssh_key_free(pubkey) ssh_key_free(privkey) - try? FileManager.default.removeItem(at: tempPubkey) - try? FileManager.default.removeItem(at: tempKey) + do { + try FileManager.default.removeItem(at: tempPubkey) + try FileManager.default.removeItem(at: tempKey) + } catch { + print("error removing file") + print(error.localizedDescription) + } return } @@ -328,7 +347,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject { var status: CInt channel = ssh_channel_new(session) - guard let channel = channel else { return } + guard let channel else { return } status = ssh_channel_open_session(channel) guard status == SSH_OK else { @@ -356,7 +375,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject { func readFromChannel() -> String? { guard connected else { return nil } - guard ssh_channel_is_open(channel) != 0 || ssh_channel_is_eof(channel) == 0 else { + guard ssh_channel_is_open(channel) == 1 && ssh_channel_is_eof(channel) == 0 else { Task { await disconnect() } return nil } @@ -376,19 +395,12 @@ class SSHHandler: @unchecked Sendable, ObservableObject { return nil } - private func logSshGetError() { - logger.critical("\(String(cString: ssh_get_error(&self.session)))") - } - - private func logCritical(_ logMessage: String) { - logger.critical("\(logMessage)") - } - func writeToChannel(_ string: String?) { - guard let string = string else { return } - guard channel != nil else { return } - guard ssh_channel_is_open(channel) != 0 else { return } - guard ssh_channel_is_eof(channel) == 0 else { return } + guard let string else { return } + guard ssh_channel_is_open(channel) == 1 && ssh_channel_is_eof(channel) == 0 else { + Task { await disconnect() } + return + } var buffer: [CChar] = [] for byte in string.utf8 { @@ -408,4 +420,13 @@ class SSHHandler: @unchecked Sendable, ObservableObject { ssh_channel_change_pty_size(channel, Int32(toCols), Int32(toRows)) // print("resized tty to \(toRows)rows and \(toCols)cols") } + + private func logSshGetError() { + guard var session = self.session else { return } + logger.critical("\(String(cString: ssh_get_error(&session)))") + } + + private func logCritical(_ logMessage: String) { + logger.critical("\(logMessage)") + } } diff --git a/ShhShell/Views/ConnectionView.swift b/ShhShell/Views/ConnectionView.swift index 94560f3..5abe7f2 100644 --- a/ShhShell/Views/ConnectionView.swift +++ b/ShhShell/Views/ConnectionView.swift @@ -18,8 +18,6 @@ struct ConnectionView: View { @State var privkeyStr: String = "" @State var showTerminal: Bool = false - @State var privPickerPresented: Bool = false - @State var pubPickerPresented: Bool = false @State var hostKeyChangedAlert: Bool = false @@ -65,26 +63,6 @@ struct ConnectionView: View { let newStr = pubkeyStr.replacingOccurrences(of: "\r\n", with: "") handler.host.publicKey = Data(newStr.utf8) } - Button() { - pubPickerPresented.toggle() - } label: { - Image(systemName: "folder") - } - .buttonStyle(.plain) - .fileImporter(isPresented: $pubPickerPresented, allowedContentTypes: [.item, .content, .data]) { (Result) in - do { - let fileURL = try Result.get() - guard fileURL.startAccessingSecurityScopedResource() else { - print("cant acces file") - return - } - defer { fileURL.stopAccessingSecurityScopedResource() } - handler.host.publicKey = try? Data(contentsOf: fileURL) - print(fileURL) - } catch { - print(error.localizedDescription) - } - } } HStack { @@ -93,27 +71,6 @@ struct ConnectionView: View { let newStr = privkeyStr.replacingOccurrences(of: "\r\n", with: "") handler.host.privateKey = Data(newStr.utf8) } - Button() { - privPickerPresented.toggle() - } label: { - Image(systemName: "folder") - } - .buttonStyle(.plain) - .fileImporter(isPresented: $privPickerPresented, allowedContentTypes: [.item, .content, .data]) { (Result) in - do { - let fileURL = try Result.get() - guard fileURL.startAccessingSecurityScopedResource() else { - print("cant access file") - return - } - defer { fileURL.stopAccessingSecurityScopedResource() } - handler.host.privateKey = try? Data(contentsOf: fileURL) - print(handler.host.privateKey ?? "") - print(fileURL) - } catch { - print(error.localizedDescription) - } - } } TextField("", text: $passphrase, prompt: Text("Passphrase (Optional)")) } diff --git a/ShhShell/Views/Terminal/SSHTerminalView.swift b/ShhShell/Views/Terminal/SSHTerminalView.swift index a12a2d1..83033b0 100644 --- a/ShhShell/Views/Terminal/SSHTerminalView.swift +++ b/ShhShell/Views/Terminal/SSHTerminalView.swift @@ -31,7 +31,7 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie while handler.connected { if let read = handler.readFromChannel() { Task { [weak self] in - guard let self = self else { return } + guard let self else { return } await self.feed(text: read) } } else { @@ -50,7 +50,7 @@ final class SSHTerminalView: TerminalView, Sendable, @preconcurrency TerminalVie while handler.connected { if let read = handler.readFromChannel() { Task { [weak self] in - guard let self = self else { return } + guard let self else { return } await self.feed(text: read) } } else {