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
This commit is contained in:
neon443
2025-06-06 21:14:11 +01:00
parent 8d68125b3f
commit 7adc2b7059
3 changed files with 141 additions and 61 deletions

View File

@@ -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<CChar>? = 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..<nprompts {
let prompt: UnsafePointer<CChar>
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<CChar> = .init(mutating: buffer)
let ptr: UnsafeMutablePointer<CChar> = .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)))")
}
}

View File

@@ -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)
}

View File

@@ -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")
)
}