mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
fix more concurrency
free session if connection failed read only once in testexec unique names for key filenmaes free pubkeys even if it fails to auth fix bitmask reading of auth methods remove handler.state from the terminal, put it inline with other status indicators
This commit is contained in:
@@ -13,7 +13,6 @@ import SwiftUI
|
|||||||
class SSHHandler: @unchecked Sendable, ObservableObject {
|
class SSHHandler: @unchecked Sendable, ObservableObject {
|
||||||
private var session: ssh_session?
|
private var session: ssh_session?
|
||||||
private var channel: ssh_channel?
|
private var channel: ssh_channel?
|
||||||
private let sshQueue = DispatchQueue(label: "SSH Queue")
|
|
||||||
|
|
||||||
@Published var title: String = ""
|
@Published var title: String = ""
|
||||||
@Published var state: SSHState = .idle
|
@Published var state: SSHState = .idle
|
||||||
@@ -49,12 +48,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
|
|
||||||
func go() {
|
func go() {
|
||||||
guard !connected else {
|
guard !connected else {
|
||||||
Task { @MainActor in
|
|
||||||
withAnimation { state = .idle }
|
withAnimation { state = .idle }
|
||||||
}
|
|
||||||
Task {
|
|
||||||
disconnect()
|
disconnect()
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +108,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
|
|
||||||
let status = ssh_connect(session)
|
let status = ssh_connect(session)
|
||||||
if status != SSH_OK {
|
if status != SSH_OK {
|
||||||
|
ssh_free(session)
|
||||||
logger.critical("connection not ok: \(status)")
|
logger.critical("connection not ok: \(status)")
|
||||||
logSshGetError()
|
logSshGetError()
|
||||||
withAnimation { state = .idle }
|
withAnimation { state = .idle }
|
||||||
@@ -123,10 +119,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
DispatchQueue.main.async {
|
|
||||||
withAnimation { self.state = .idle }
|
withAnimation { self.state = .idle }
|
||||||
withAnimation { self.testSuceeded = nil }
|
withAnimation { self.testSuceeded = nil }
|
||||||
}
|
|
||||||
|
|
||||||
//send eof if open
|
//send eof if open
|
||||||
if ssh_channel_is_open(channel) == 1 {
|
if ssh_channel_is_open(channel) == 1 {
|
||||||
@@ -161,12 +155,10 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
|
|
||||||
func testExec() {
|
func testExec() {
|
||||||
defer {
|
defer {
|
||||||
Task { @MainActor in
|
|
||||||
let result = self.testSuceeded
|
let result = self.testSuceeded
|
||||||
disconnect()
|
disconnect()
|
||||||
withAnimation { testSuceeded = result }
|
withAnimation { testSuceeded = result }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !checkAuth(state) {
|
if !checkAuth(state) {
|
||||||
go()
|
go()
|
||||||
@@ -211,15 +203,12 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nbytes = ssh_channel_read(
|
nbytes = ssh_channel_read_nonblocking(
|
||||||
testChannel,
|
testChannel,
|
||||||
&buffer,
|
&buffer,
|
||||||
UInt32(buffer.count),
|
UInt32(buffer.count),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
while nbytes > 0 {
|
|
||||||
nbytes = ssh_channel_read_nonblocking(testChannel, &buffer, UInt32(buffer.count), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if nbytes < 0 {
|
if nbytes < 0 {
|
||||||
ssh_channel_close(testChannel)
|
ssh_channel_close(testChannel)
|
||||||
@@ -246,8 +235,8 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
|
|
||||||
let fileManager = FileManager.default
|
let fileManager = FileManager.default
|
||||||
let tempDir = fileManager.temporaryDirectory
|
let tempDir = fileManager.temporaryDirectory
|
||||||
let tempPubkey = tempDir.appendingPathComponent("key.pub")
|
let tempPubkey = tempDir.appendingPathComponent("\(UUID())key.pub")
|
||||||
let tempKey = tempDir.appendingPathComponent("key")
|
let tempKey = tempDir.appendingPathComponent("\(UUID())key")
|
||||||
|
|
||||||
fileManager.createFile(atPath: tempPubkey.path(), contents: nil)
|
fileManager.createFile(atPath: tempPubkey.path(), contents: nil)
|
||||||
fileManager.createFile(atPath: tempKey.path(), contents: nil)
|
fileManager.createFile(atPath: tempKey.path(), contents: nil)
|
||||||
@@ -272,6 +261,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
if ssh_pki_import_pubkey_file(tempPubkey.path(), &pubkey) != 0 {
|
if ssh_pki_import_pubkey_file(tempPubkey.path(), &pubkey) != 0 {
|
||||||
throw .importPrivkeyError
|
throw .importPrivkeyError
|
||||||
}
|
}
|
||||||
|
defer { ssh_key_free(pubkey) }
|
||||||
|
|
||||||
if ssh_userauth_try_publickey(session, nil, pubkey) != 0 {
|
if ssh_userauth_try_publickey(session, nil, pubkey) != 0 {
|
||||||
throw .pubkeyRejected
|
throw .pubkeyRejected
|
||||||
@@ -281,6 +271,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
if ssh_pki_import_privkey_file(tempKey.path(), pass, nil, nil, &privkey) != 0 {
|
if ssh_pki_import_privkey_file(tempKey.path(), pass, nil, nil, &privkey) != 0 {
|
||||||
throw .importPrivkeyError
|
throw .importPrivkeyError
|
||||||
}
|
}
|
||||||
|
defer { ssh_key_free(privkey) }
|
||||||
|
|
||||||
if (ssh_userauth_publickey(session, nil, privkey) != 0) {
|
if (ssh_userauth_publickey(session, nil, privkey) != 0) {
|
||||||
throw .privkeyRejected
|
throw .privkeyRejected
|
||||||
@@ -289,8 +280,6 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
//if u got this far, youre authed!
|
//if u got this far, youre authed!
|
||||||
withAnimation { state = .authorized }
|
withAnimation { state = .authorized }
|
||||||
|
|
||||||
ssh_key_free(pubkey)
|
|
||||||
ssh_key_free(privkey)
|
|
||||||
do {
|
do {
|
||||||
try FileManager.default.removeItem(at: tempPubkey)
|
try FileManager.default.removeItem(at: tempPubkey)
|
||||||
try FileManager.default.removeItem(at: tempKey)
|
try FileManager.default.removeItem(at: tempKey)
|
||||||
@@ -341,7 +330,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
let allAuths = zip(allAuthDescriptions, allAuthRaws)
|
let allAuths = zip(allAuthDescriptions, allAuthRaws)
|
||||||
|
|
||||||
for authMethod in allAuths {
|
for authMethod in allAuths {
|
||||||
if authMethod.1 == recievedMethod {
|
if (recievedMethod & Int32(authMethod.1)) != 0 {
|
||||||
print(authMethod.0)
|
print(authMethod.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,7 +370,7 @@ class SSHHandler: @unchecked Sendable, ObservableObject {
|
|||||||
func readFromChannel() -> String? {
|
func readFromChannel() -> String? {
|
||||||
guard connected else { return nil }
|
guard connected else { return nil }
|
||||||
guard ssh_channel_is_open(channel) == 1 && ssh_channel_is_eof(channel) == 0 else {
|
guard ssh_channel_is_open(channel) == 1 && ssh_channel_is_eof(channel) == 0 else {
|
||||||
Task { disconnect() }
|
disconnect()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ struct ConnectionView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
List {
|
List {
|
||||||
Text("\(handler.state)")
|
|
||||||
Section {
|
Section {
|
||||||
HStack {
|
HStack {
|
||||||
Text(handler.connected ? "connected" : "not connected")
|
Text(handler.connected ? "connected" : "not connected")
|
||||||
@@ -32,6 +31,7 @@ struct ConnectionView: View {
|
|||||||
|
|
||||||
Text(checkAuth(handler.state) ? "authorized" : "unauthorized")
|
Text(checkAuth(handler.state) ? "authorized" : "unauthorized")
|
||||||
.modifier(foregroundColorStyle(checkAuth(handler.state) ? .green : .red))
|
.modifier(foregroundColorStyle(checkAuth(handler.state) ? .green : .red))
|
||||||
|
Text("\(handler.state)")
|
||||||
}
|
}
|
||||||
TextField("address", text: $handler.host.address)
|
TextField("address", text: $handler.host.address)
|
||||||
.textFieldStyle(.roundedBorder)
|
.textFieldStyle(.roundedBorder)
|
||||||
@@ -133,7 +133,6 @@ struct ConnectionView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fullScreenCover(isPresented: $showTerminal) {
|
.fullScreenCover(isPresented: $showTerminal) {
|
||||||
Text("\(handler.state)")
|
|
||||||
ShellView(handler: handler)
|
ShellView(handler: handler)
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
|
|||||||
Reference in New Issue
Block a user