diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index d47465b..79634ad 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -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 = ""; }; A92538CF2DEE0745007E0A18 /* ShhShellUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShhShellUITestsLaunchTests.swift; sourceTree = ""; }; 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 = ""; }; + A93143C22DF61F5700FCD5DB /* ShhShell.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShhShell.entitlements; sourceTree = ""; }; + A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = ""; }; 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 = ""; }; A95FAA512DF4B62100DE2F5A /* openssl.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = openssl.xcframework; path = Frameworks/openssl.xcframework; sourceTree = ""; }; @@ -75,7 +79,6 @@ A95FAA5B2DF4B7A000DE2F5A /* ci_pre_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_pre_xcodebuild.sh; sourceTree = ""; }; A95FAA5C2DF4B7A300DE2F5A /* ci_prost_xcodebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ci_prost_xcodebuild.sh; sourceTree = ""; }; A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = ""; }; - A9C897F02DF1AB5700EF9A5F /* ShellHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellHandler.swift; sourceTree = ""; }; /* 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 = ""; @@ -163,6 +166,7 @@ isa = PBXGroup; children = ( A92538C52DEE0742007E0A18 /* ContentView.swift */, + A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */, ); path = Views; sourceTree = ""; @@ -175,6 +179,15 @@ path = Resources; sourceTree = ""; }; + A93143C12DF61E8500FCD5DB /* SSH */ = { + isa = PBXGroup; + children = ( + A93143BF2DF61B3200FCD5DB /* Host.swift */, + A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */, + ); + path = SSH; + sourceTree = ""; + }; 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", diff --git a/ShhShell/SSH/Host.swift b/ShhShell/SSH/Host.swift new file mode 100644 index 0000000..37b5257 --- /dev/null +++ b/ShhShell/SSH/Host.swift @@ -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 +} diff --git a/ShhShell/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift similarity index 90% rename from ShhShell/SSHHandler.swift rename to ShhShell/SSH/SSHHandler.swift index 3afbde8..69a70b1 100644 --- a/ShhShell/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -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)!) } } diff --git a/ShhShell/ShellHandler.swift b/ShhShell/ShellHandler.swift deleted file mode 100644 index bc365c1..0000000 --- a/ShhShell/ShellHandler.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// ShellHandler.swift -// ShhShell -// -// Created by neon443 on 05/06/2025. -// - -import Foundation diff --git a/ShhShell/ShhShell.entitlements b/ShhShell/ShhShell.entitlements new file mode 100644 index 0000000..c280ba7 --- /dev/null +++ b/ShhShell/ShhShell.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.icloud-container-identifiers + + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)$(CFBundleIdentifier) + + diff --git a/ShhShell/ShhShellApp.swift b/ShhShell/ShhShellApp.swift index 6cd771e..b8a1c4e 100644 --- a/ShhShell/ShhShellApp.swift +++ b/ShhShell/ShhShellApp.swift @@ -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 { diff --git a/ShhShell/Views/ContentView.swift b/ShhShell/Views/ContentView.swift index 223c2cd..6889008 100644 --- a/ShhShell/Views/ContentView.swift +++ b/ShhShell/Views/ContentView.swift @@ -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()) ) } diff --git a/ShhShell/Views/ViewModifiers.swift b/ShhShell/Views/ViewModifiers.swift new file mode 100644 index 0000000..fb1c915 --- /dev/null +++ b/ShhShell/Views/ViewModifiers.swift @@ -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) + } + } +}