Wrote a Host Protocol for easy stroing of hosts

a debugHost for reusable root:root@localhost:2222
blankHost for - well - blank hosts
gonna add userdefaults
added iclodu entitlement
added viewmodifier: foregroundStyle if 17.0+ and foregroundColor for else
This commit is contained in:
neon443
2025-06-08 20:54:49 +01:00
parent e786d31da9
commit e440168a28
8 changed files with 140 additions and 52 deletions

View File

@@ -15,13 +15,14 @@
A92538D12DEE0745007E0A18 /* ShhShellUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538CE2DEE0745007E0A18 /* ShhShellUITests.swift */; }; A92538D12DEE0745007E0A18 /* ShhShellUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538CE2DEE0745007E0A18 /* ShhShellUITests.swift */; };
A92538D22DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */; }; A92538D22DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */; };
A93143BE2DF4D0B300FCD5DB /* libpthread.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = A93143BD2DF4D0A700FCD5DB /* libpthread.tbd */; }; A93143BE2DF4D0B300FCD5DB /* libpthread.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = A93143BD2DF4D0A700FCD5DB /* libpthread.tbd */; };
A93143C02DF61B3200FCD5DB /* Host.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93143BF2DF61B3200FCD5DB /* Host.swift */; };
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */; };
A95FAA472DF3884B00DE2F5A /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = A95FAA462DF3884B00DE2F5A /* Config.xcconfig */; }; A95FAA472DF3884B00DE2F5A /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = A95FAA462DF3884B00DE2F5A /* Config.xcconfig */; };
A95FAA542DF4B62900DE2F5A /* LibSSH.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */; }; A95FAA542DF4B62900DE2F5A /* LibSSH.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */; };
A95FAA552DF4B62900DE2F5A /* LibSSH.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; A95FAA552DF4B62900DE2F5A /* LibSSH.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A95FAA562DF4B62A00DE2F5A /* openssl.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA512DF4B62100DE2F5A /* openssl.xcframework */; }; A95FAA562DF4B62A00DE2F5A /* openssl.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA512DF4B62100DE2F5A /* openssl.xcframework */; };
A95FAA572DF4B62A00DE2F5A /* openssl.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA512DF4B62100DE2F5A /* openssl.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; A95FAA572DF4B62A00DE2F5A /* openssl.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A95FAA512DF4B62100DE2F5A /* openssl.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; }; A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; };
A9C897F12DF1AB5700EF9A5F /* ShellHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897F02DF1AB5700EF9A5F /* ShellHandler.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -68,6 +69,9 @@
A92538CE2DEE0745007E0A18 /* ShhShellUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShhShellUITests.swift; sourceTree = "<group>"; }; A92538CE2DEE0745007E0A18 /* ShhShellUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShhShellUITests.swift; sourceTree = "<group>"; };
A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShhShellUITestsLaunchTests.swift; sourceTree = "<group>"; }; A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShhShellUITestsLaunchTests.swift; sourceTree = "<group>"; };
A93143BD2DF4D0A700FCD5DB /* libpthread.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpthread.tbd; path = usr/lib/libpthread.tbd; sourceTree = SDKROOT; }; A93143BD2DF4D0A700FCD5DB /* libpthread.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpthread.tbd; path = usr/lib/libpthread.tbd; sourceTree = SDKROOT; };
A93143BF2DF61B3200FCD5DB /* Host.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Host.swift; sourceTree = "<group>"; };
A93143C22DF61F5700FCD5DB /* ShhShell.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShhShell.entitlements; sourceTree = "<group>"; };
A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
A95FAA462DF3884B00DE2F5A /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = SOURCE_ROOT; }; A95FAA462DF3884B00DE2F5A /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = SOURCE_ROOT; };
A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = LibSSH.xcframework; path = Frameworks/LibSSH.xcframework; sourceTree = "<group>"; }; A95FAA502DF4B62100DE2F5A /* LibSSH.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = LibSSH.xcframework; path = Frameworks/LibSSH.xcframework; sourceTree = "<group>"; };
A95FAA512DF4B62100DE2F5A /* openssl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = openssl.xcframework; path = Frameworks/openssl.xcframework; sourceTree = "<group>"; }; A95FAA512DF4B62100DE2F5A /* openssl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = openssl.xcframework; path = Frameworks/openssl.xcframework; sourceTree = "<group>"; };
@@ -75,7 +79,6 @@
A95FAA5B2DF4B7A000DE2F5A /* ci_pre_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_pre_xcodebuild.sh; sourceTree = "<group>"; }; A95FAA5B2DF4B7A000DE2F5A /* ci_pre_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_pre_xcodebuild.sh; sourceTree = "<group>"; };
A95FAA5C2DF4B7A300DE2F5A /* ci_prost_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_prost_xcodebuild.sh; sourceTree = "<group>"; }; A95FAA5C2DF4B7A300DE2F5A /* ci_prost_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_prost_xcodebuild.sh; sourceTree = "<group>"; };
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; }; A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
A9C897F02DF1AB5700EF9A5F /* ShellHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellHandler.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -134,10 +137,10 @@
A92538C72DEE0742007E0A18 /* ShhShell */ = { A92538C72DEE0742007E0A18 /* ShhShell */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A93143C22DF61F5700FCD5DB /* ShhShell.entitlements */,
A92538C62DEE0742007E0A18 /* ShhShellApp.swift */, A92538C62DEE0742007E0A18 /* ShhShellApp.swift */,
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */,
A9C897F02DF1AB5700EF9A5F /* ShellHandler.swift */,
A92538D32DEE0749007E0A18 /* Views */, A92538D32DEE0749007E0A18 /* Views */,
A93143C12DF61E8500FCD5DB /* SSH */,
); );
path = ShhShell; path = ShhShell;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -163,6 +166,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A92538C52DEE0742007E0A18 /* ContentView.swift */, A92538C52DEE0742007E0A18 /* ContentView.swift */,
A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -175,6 +179,15 @@
path = Resources; path = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
A93143C12DF61E8500FCD5DB /* SSH */ = {
isa = PBXGroup;
children = (
A93143BF2DF61B3200FCD5DB /* Host.swift */,
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */,
);
path = SSH;
sourceTree = "<group>";
};
A95FAA582DF4B71F00DE2F5A /* ci_scripts */ = { A95FAA582DF4B71F00DE2F5A /* ci_scripts */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -336,10 +349,11 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */, A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
A93143C02DF61B3200FCD5DB /* Host.swift in Sources */,
A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */, A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */,
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */, A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */,
A9C897F12DF1AB5700EF9A5F /* ShellHandler.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -504,6 +518,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = ShhShell/ShhShell.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(BUILD)"; CURRENT_PROJECT_VERSION = "$(BUILD)";
DEVELOPMENT_TEAM = 8JGND254B7; DEVELOPMENT_TEAM = 8JGND254B7;
@@ -515,7 +530,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 14;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@@ -534,6 +549,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = ShhShell/ShhShell.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(BUILD)"; CURRENT_PROJECT_VERSION = "$(BUILD)";
DEVELOPMENT_TEAM = 8JGND254B7; DEVELOPMENT_TEAM = 8JGND254B7;
@@ -545,7 +561,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 14;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

54
ShhShell/SSH/Host.swift Normal file
View File

@@ -0,0 +1,54 @@
//
// Host.swift
// ShhShell
//
// Created by neon443 on 08/06/2025.
//
import Foundation
protocol HostPr: Codable {
var address: String { get set }
var port: Int { get set }
var username: String { get set }
var password: String { get set }
var key: Data? { get set }
}
struct Host: HostPr {
var address: String = "address"
var port: Int
var username: String
var password: String
var key: Data?
init(
address: String,
port: Int = 22,
username: String,
password: String,
hostkey: Data? = nil
) {
self.address = address
self.port = port
self.username = username
self.password = password
self.key = hostkey
}
}
struct blankHost: HostPr {
var address: String = ""
var port: Int = 22
var username: String = ""
var password: String = ""
var key: Data? = nil
}
struct debugHost: HostPr {
var address: String = "localhost"
var port: Int = 2222
var username: String = "root"
var password: String = "root"
var key: Data? = nil
}

View File

@@ -14,30 +14,18 @@ class SSHHandler: ObservableObject {
private var channel: ssh_channel? private var channel: ssh_channel?
@Published var authorized: Bool = false @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? @Published var host: HostPr
private let userDefaults = NSUbiquitousKeyValueStore.default
private let logger = Logger(subsystem: "xy", category: "sshHandler") private let logger = Logger(subsystem: "xy", category: "sshHandler")
init( init(
username: String = "", host: HostPr
password: String = "",
address: String = "",
port: Int = 22
) { ) {
self.username = username self.host = host
self.password = password
self.address = address
self.port = port
#if DEBUG #if DEBUG
self.username = "root" self.host = debugHost()
self.password = "root"
self.address = "localhost"
self.port = 2222
#endif #endif
} }
@@ -57,7 +45,7 @@ class SSHHandler: ObservableObject {
func connect() -> Bool { func connect() -> Bool {
defer { defer {
getAuthMethods() getAuthMethods()
self.hostkey = getHostkey() self.host.key = getHostkey()
} }
var verbosity: Int = 0 var verbosity: Int = 0
@@ -67,9 +55,9 @@ class SSHHandler: ObservableObject {
return false return false
} }
ssh_options_set(session, SSH_OPTIONS_HOST, address) ssh_options_set(session, SSH_OPTIONS_HOST, host.address)
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity)
ssh_options_set(session, SSH_OPTIONS_PORT, &port) ssh_options_set(session, SSH_OPTIONS_PORT, &host.port)
let status = ssh_connect(session) let status = ssh_connect(session)
if status != SSH_OK { if status != SSH_OK {
@@ -89,7 +77,7 @@ class SSHHandler: ObservableObject {
ssh_free(session) ssh_free(session)
session = nil session = nil
authorized = false authorized = false
hostkey = nil host.key = nil
} }
func testExec() -> Bool { func testExec() -> Bool {
@@ -170,7 +158,7 @@ class SSHHandler: ObservableObject {
func authWithPw() -> Bool { func authWithPw() -> Bool {
var status: CInt var status: CInt
status = ssh_userauth_password(session, username, password) status = ssh_userauth_password(session, host.username, host.password)
guard status == SSH_AUTH_SUCCESS.rawValue else { guard status == SSH_AUTH_SUCCESS.rawValue else {
print("ssh pw auth error") print("ssh pw auth error")
logSshGetError() logSshGetError()
@@ -245,7 +233,7 @@ class SSHHandler: ObservableObject {
func getAuthMethods() { func getAuthMethods() {
var method: CInt var method: CInt
method = ssh_userauth_list(session, username) method = ssh_userauth_list(session, host.username)
} }
func openShell() { func openShell() {
@@ -287,7 +275,7 @@ class SSHHandler: ObservableObject {
write(1, buffer, Int(nbytes)) write(1, buffer, Int(nbytes))
let data = Data(bytes: buffer, count: buffer.count) let data = Data(bytes: buffer, count: buffer.count)
print(String(data: data, encoding: .utf8)) print(String(data: data, encoding: .utf8)!)
} }
} }

View File

@@ -1,8 +0,0 @@
//
// ShellHandler.swift
// ShhShell
//
// Created by neon443 on 05/06/2025.
//
import Foundation

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array/>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
</dict>
</plist>

View File

@@ -9,7 +9,7 @@ import SwiftUI
@main @main
struct ShhShellApp: App { struct ShhShellApp: App {
@StateObject var sshHandler: SSHHandler = SSHHandler(username: "", password: "") @StateObject var sshHandler: SSHHandler = SSHHandler(host: blankHost())
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {

View File

@@ -17,36 +17,36 @@ struct ContentView: View {
var body: some View { var body: some View {
VStack { VStack {
Text(connected ? "connected" : "not connected") Text(connected ? "connected" : "not connected")
.foregroundStyle(connected ? .green : .red) .modifier(foregroundColorStyle(connected ? .green : .red))
Text(handler.authorized ? "authorized" : "unauthorized") Text(handler.authorized ? "authorized" : "unauthorized")
.foregroundStyle(handler.authorized ? .green : .red) .modifier(foregroundColorStyle(handler.authorized ? .green : .red))
if let testSucceded = testSucceded { if let testSucceded = testSucceded {
Image(systemName: testSucceded ? "checkmark.circle" : "xmark.circle") Image(systemName: testSucceded ? "checkmark.circle" : "xmark.circle")
.foregroundStyle(testSucceded ? .green : .red) .modifier(foregroundColorStyle(testSucceded ? .green : .red))
} }
if handler.hostkey != nil { if handler.host.key != nil {
Text("Hostkey: \(handler.hostkey!.base64EncodedString())") Text("Hostkey: \(handler.host.key!.base64EncodedString())")
} }
TextField("address", text: $handler.address) TextField("address", text: $handler.host.address)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
TextField( TextField(
"port", "port",
text: Binding( text: Binding(
get: { String(handler.port) }, get: { String(handler.host.port) },
set: { handler.port = Int($0) ?? 22} ) set: { handler.host.port = Int($0) ?? 22} )
) )
.keyboardType(.numberPad) .keyboardType(.numberPad)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
TextField("username", text: $handler.username) TextField("username", text: $handler.host.username)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
TextField("password", text: $handler.password) TextField("password", text: $handler.host.password)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
Button("connect") { Button("connect") {
@@ -90,6 +90,6 @@ struct ContentView: View {
#Preview { #Preview {
ContentView( ContentView(
handler: SSHHandler(username: "root", password: "root") handler: SSHHandler(host: debugHost())
) )
} }

View File

@@ -0,0 +1,28 @@
//
// ViewModifiers.swift
// ShhShell
//
// Created by neon443 on 08/06/2025.
//
import Foundation
import SwiftUI
struct foregroundColorStyle: ViewModifier {
var color: Color?
init(_ color: Color?) {
self.color = color
}
func body(content: Content) -> some View {
if #available(iOS 17.0, *) {
if let color = color {
content.foregroundStyle(color)
}
content
} else {
content.foregroundColor(color)
}
}
}