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 */; };
A92538D22DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */; };
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 */; };
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, ); }; };
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, ); }; };
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 */
/* Begin PBXContainerItemProxy section */
@@ -68,6 +69,9 @@
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>"; };
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; };
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>"; };
@@ -75,7 +79,6 @@
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>"; };
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 */
/* Begin PBXFrameworksBuildPhase section */
@@ -134,10 +137,10 @@
A92538C72DEE0742007E0A18 /* ShhShell */ = {
isa = PBXGroup;
children = (
A93143C22DF61F5700FCD5DB /* ShhShell.entitlements */,
A92538C62DEE0742007E0A18 /* ShhShellApp.swift */,
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */,
A9C897F02DF1AB5700EF9A5F /* ShellHandler.swift */,
A92538D32DEE0749007E0A18 /* Views */,
A93143C12DF61E8500FCD5DB /* SSH */,
);
path = ShhShell;
sourceTree = "<group>";
@@ -163,6 +166,7 @@
isa = PBXGroup;
children = (
A92538C52DEE0742007E0A18 /* ContentView.swift */,
A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -175,6 +179,15 @@
path = Resources;
sourceTree = "<group>";
};
A93143C12DF61E8500FCD5DB /* SSH */ = {
isa = PBXGroup;
children = (
A93143BF2DF61B3200FCD5DB /* Host.swift */,
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */,
);
path = SSH;
sourceTree = "<group>";
};
A95FAA582DF4B71F00DE2F5A /* ci_scripts */ = {
isa = PBXGroup;
children = (
@@ -336,10 +349,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
A93143C02DF61B3200FCD5DB /* Host.swift in Sources */,
A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */,
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */,
A9C897F12DF1AB5700EF9A5F /* ShellHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -504,6 +518,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = ShhShell/ShhShell.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(BUILD)";
DEVELOPMENT_TEAM = 8JGND254B7;
@@ -515,7 +530,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 14;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -534,6 +549,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = ShhShell/ShhShell.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(BUILD)";
DEVELOPMENT_TEAM = 8JGND254B7;
@@ -545,7 +561,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 14;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@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?
@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")
init(
username: String = "",
password: String = "",
address: String = "",
port: Int = 22
host: HostPr
) {
self.username = username
self.password = password
self.address = address
self.port = port
self.host = host
#if DEBUG
self.username = "root"
self.password = "root"
self.address = "localhost"
self.port = 2222
self.host = debugHost()
#endif
}
@@ -57,7 +45,7 @@ class SSHHandler: ObservableObject {
func connect() -> Bool {
defer {
getAuthMethods()
self.hostkey = getHostkey()
self.host.key = getHostkey()
}
var verbosity: Int = 0
@@ -67,9 +55,9 @@ class SSHHandler: ObservableObject {
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_PORT, &port)
ssh_options_set(session, SSH_OPTIONS_PORT, &host.port)
let status = ssh_connect(session)
if status != SSH_OK {
@@ -89,7 +77,7 @@ class SSHHandler: ObservableObject {
ssh_free(session)
session = nil
authorized = false
hostkey = nil
host.key = nil
}
func testExec() -> Bool {
@@ -170,7 +158,7 @@ class SSHHandler: ObservableObject {
func authWithPw() -> Bool {
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 {
print("ssh pw auth error")
logSshGetError()
@@ -245,7 +233,7 @@ class SSHHandler: ObservableObject {
func getAuthMethods() {
var method: CInt
method = ssh_userauth_list(session, username)
method = ssh_userauth_list(session, host.username)
}
func openShell() {
@@ -287,7 +275,7 @@ class SSHHandler: ObservableObject {
write(1, buffer, Int(nbytes))
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
struct ShhShellApp: App {
@StateObject var sshHandler: SSHHandler = SSHHandler(username: "", password: "")
@StateObject var sshHandler: SSHHandler = SSHHandler(host: blankHost())
var body: some Scene {
WindowGroup {

View File

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