From 63bf3241a191c37411c69dedca0bc9599bf51f2d Mon Sep 17 00:00:00 2001 From: Thomas Evensen <thomeven@gmail.com> Date: Tue, 13 Aug 2024 19:19:37 +0200 Subject: [PATCH] Initial create --- Sources/SSHCreateKey/SSHCreateKey.swift | 268 ++++++++++++++++++ .../DecodeTestUserConfiguration.swift | 66 +++++ Tests/SSHCreateKeyTests/DecodeTestdata.swift | 99 +++++++ .../ReadTestdataFromGitHub.swift | 40 +++ .../SSHCreateKeyTests/SSHCreateKeyTests.swift | 25 +- .../TestSharedReference.swift | 67 +++++ .../TestSynchronizeConfiguration.swift | 140 +++++++++ .../TestUserConfiguration.swift | 172 +++++++++++ .../TestdataFromGitHub.swift | 41 +++ 9 files changed, 916 insertions(+), 2 deletions(-) create mode 100644 Tests/SSHCreateKeyTests/DecodeTestUserConfiguration.swift create mode 100644 Tests/SSHCreateKeyTests/DecodeTestdata.swift create mode 100644 Tests/SSHCreateKeyTests/ReadTestdataFromGitHub.swift create mode 100644 Tests/SSHCreateKeyTests/TestSharedReference.swift create mode 100644 Tests/SSHCreateKeyTests/TestSynchronizeConfiguration.swift create mode 100644 Tests/SSHCreateKeyTests/TestUserConfiguration.swift create mode 100644 Tests/SSHCreateKeyTests/TestdataFromGitHub.swift diff --git a/Sources/SSHCreateKey/SSHCreateKey.swift b/Sources/SSHCreateKey/SSHCreateKey.swift index 08b22b8..12d44f9 100644 --- a/Sources/SSHCreateKey/SSHCreateKey.swift +++ b/Sources/SSHCreateKey/SSHCreateKey.swift @@ -1,2 +1,270 @@ // The Swift Programming Language // https://docs.swift.org/swift-book +import Foundation + +@MainActor +public final class SSHCreateKey { + + // var offsiteServer = "" + // var offsiteUsername = "" + + var sharedsshport: String? + var sharedsshkeypathandidentityfile: String? + + public var rsaStringPath: String? + // Arrays listing all key files + public var keyFileStrings: [String]? { + let fm = FileManager.default + if let atpath = keypathonly { + var array = [String]() + do { + for files in try fm.contentsOfDirectory(atPath: atpath) { + array.append(files) + } + return array + } catch { + return nil + } + } + return nil + } + + // Path to ssh keypath + public var sshkeypathandidentityfile: String? { + if let sharedsshkeypathandidentityfile, + let userHomeDirectoryPath + { + if sharedsshkeypathandidentityfile.first == "~" { + // must drop identityfile and then set rootpath + // also drop the "~" character + let sshkeypathandidentityfilesplit = sharedsshkeypathandidentityfile.split(separator: "/") + guard sshkeypathandidentityfilesplit.count > 2 else { + // If anything goes wrong set to default global values + return userHomeDirectoryPath + "/.ssh" + } + return userHomeDirectoryPath + sshkeypathandidentityfilesplit.joined(separator: "/").dropFirst() + + } else { + // If anything goes wrong set to default global values + return userHomeDirectoryPath + "/.ssh" + } + } else { + return (userHomeDirectoryPath ?? "") + "/.ssh" + } + } + + // SSH identityfile with full keypath if NOT default is used + // If default, only return defalt value + public var identityfile: String? { + if let sharedsshkeypathandidentityfile { + if sharedsshkeypathandidentityfile.first == "~" { + // must drop identityfile and then set rootpath + // also drop the "~" character + let sshkeypathandidentityfilesplit = sharedsshkeypathandidentityfile.split(separator: "/") + guard sshkeypathandidentityfilesplit.count > 2 else { + // If anything goes wrong set to default global values + return "id_rsa" + } + return String(sshkeypathandidentityfilesplit[sshkeypathandidentityfilesplit.count - 1]) + } else { + // If anything goes wrong set to default global values + return "id_rsa" + } + } else { + return "id_rsa" + } + } + + // Used when creating ssh keypath + public var keypathonly: String? { + if let sharedsshkeypathandidentityfile, + let userHomeDirectoryPath + { + if sharedsshkeypathandidentityfile.first == "~" { + // must drop identityfile and then set rootpath + // also drop the "~" character + var sshkeypathandidentityfilesplit = sharedsshkeypathandidentityfile.split(separator: "/") + guard sshkeypathandidentityfilesplit.count > 2 else { + // If anything goes wrong set to default global values + return NSHomeDirectory() + } + sshkeypathandidentityfilesplit.remove(at: sshkeypathandidentityfilesplit.count - 1) + return userHomeDirectoryPath + + String(sshkeypathandidentityfilesplit.joined(separator: "/").dropFirst()) + + } else { + // If anything goes wrong set to default global values + return userHomeDirectoryPath + } + } else { + return userHomeDirectoryPath + } + } + + public var userHomeDirectoryPath: String? { + let pw = getpwuid(getuid()) + if let home = pw?.pointee.pw_dir { + let homePath = FileManager.default.string(withFileSystemRepresentation: home, length: Int(strlen(home))) + return homePath + } else { + return nil + } + } + + // Create SSH catalog + // If ssh catalog exists - bail out, no need to create + public func createsshkeyrootpath() { + let fm = FileManager.default + if let keypathonly, + let userHomeDirectoryPath + { + let sshkeypathString = userHomeDirectoryPath + "/." + keypathonly + guard fm.keypathlocationExists(at: sshkeypathString, kind: .folder) == false else { + return + } + + let userHomeDirectoryPathURL = URL(fileURLWithPath: userHomeDirectoryPath) + let sshkeypathlURL = userHomeDirectoryPathURL.appendingPathComponent("/." + keypathonly) + + do { + try fm.createDirectory(at: sshkeypathlURL, withIntermediateDirectories: true, attributes: nil) + } catch let e { + let error = e + // propogateerror(error: error) + return + } + } + } + + // Set parameters for ssh-copy-id for copy public ssh key to server + // ssh-address = "backup@server.com" + // ssh-copy-id -i $ssh-keypath -p port $ssh-address + public func argumentssshcopyid(offsiteServer: String, + offsiteUsername: String) -> String { + var args = [String]() + let command = "/usr/bin/ssh-copy-id" + args.append(command) + args.append("-i") + if let sharedsshkeypathandidentityfile, + let sharedsshport, + sharedsshkeypathandidentityfile.isEmpty == false, + sharedsshport != "-1" + { + args.append(sharedsshkeypathandidentityfile) + args.append("-p") + args.append(sharedsshport) + } + args.append( offsiteUsername + "@" + offsiteServer) + return args.joined(separator: " ") + } + + // Check if pub key exists on remote server + // ssh -p port -i $ssh-keypath $ssh-address + public func argumentscheckremotepubkey(offsiteServer: String, + offsiteUsername: String) -> String { + var args = [String]() + let command = "/usr/bin/ssh" + args.append(command) + if let sharedsshport, sharedsshport != "-1" { + args.append("-p") + args.append(sharedsshport) + } + args.append("-i") + if let sharedsshkeypathandidentityfile, + sharedsshkeypathandidentityfile.isEmpty == false + { + args.append(sharedsshkeypathandidentityfile) + } + + args.append( offsiteUsername + "@" + offsiteServer) + return args.joined(separator: " ") + } + + // Create local key with ssh-keygen + // Generate a passwordless RSA keyfile -N sets password, "" makes it blank + // ssh-keygen -t rsa -N "" -f $ssh-keypath + public func argumentscreatekey() -> [String]? { + var args = [String]() + args.append("-t") + args.append("rsa") + args.append("-N") + args.append("") + args.append("-f") + if let sharedsshkeypathandidentityfile, + sharedsshkeypathandidentityfile.isEmpty == false + { + args.append(sharedsshkeypathandidentityfile) + } + return args + } + + // Check if rsa pub key exists + public func islocalpublicrsakeypresent() throws -> Bool { + guard keyFileStrings != nil else { return false } + guard keyFileStrings?.filter({ $0.contains(identityfile ?? "") }).count ?? 0 > 0 else { return false } + guard keyFileStrings?.filter({ $0.contains((identityfile ?? "") + ".pub") }).count ?? 0 > 0 else { + throw SshError.sshkeys + } + rsaStringPath = keyFileStrings?.filter { $0.contains((identityfile ?? "") + ".pub") }[0] + guard rsaStringPath?.count ?? 0 > 0 else { return false } + throw SshError.sshkeys + } + + public func validatepublickeypresent() -> Bool { + guard keyFileStrings != nil else { return false } + guard keyFileStrings?.filter({ $0.contains(identityfile ?? "") }).count ?? 0 > 0 else { return false } + guard keyFileStrings?.filter({ $0.contains((identityfile ?? "") + ".pub") }).count ?? 0 > 0 else { + return true + } + rsaStringPath = keyFileStrings?.filter { $0.contains((identityfile ?? "") + ".pub") }[0] + guard rsaStringPath?.count ?? 0 > 0 else { return false } + return true + } + + public init( sharedsshport: String?, + sharedsshkeypathandidentityfile: String?) + { + self.sharedsshport = sharedsshport + self.sharedsshkeypathandidentityfile = sharedsshkeypathandidentityfile + } +} + +extension FileManager { + func keypathlocationExists(at path: String, kind: LocationKind) -> Bool { + var isFolder: ObjCBool = false + + guard fileExists(atPath: path, isDirectory: &isFolder) else { + return false + } + + switch kind { + case .file: return !isFolder.boolValue + case .folder: return isFolder.boolValue + } + } +} + +/// Enum describing various kinds of locations that can be found on a file system. +public enum LocationKind { + /// A file can be found at the location. + case file + /// A folder can be found at the location. + case folder +} + +public enum SshError: LocalizedError { + case notvalidpath + case sshkeys + case noslash + + public var errorDescription: String? { + switch self { + case .notvalidpath: + "SSH keypath is not valid" + case .sshkeys: + "SSH RSA keys exist, cannot create" + case .noslash: + "SSH keypath must be like ~/.ssh_keypath/identityfile" + } + } +} diff --git a/Tests/SSHCreateKeyTests/DecodeTestUserConfiguration.swift b/Tests/SSHCreateKeyTests/DecodeTestUserConfiguration.swift new file mode 100644 index 0000000..4511180 --- /dev/null +++ b/Tests/SSHCreateKeyTests/DecodeTestUserConfiguration.swift @@ -0,0 +1,66 @@ +// +// DecodeTestUserConfiguration.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +struct DecodeTestUserConfiguration: Codable { + let rsyncversion3: Int? + // Detailed logging + let addsummarylogrecord: Int? + // Logging to logfile + let logtofile: Int? + // Monitor network connection + let monitornetworkconnection: Int? + // local path for rsync + let localrsyncpath: String? + // temporary path for restore + let pathforrestore: String? + // days for mark days since last synchronize + let marknumberofdayssince: String? + // Global ssh keypath and port + let sshkeypathandidentityfile: String? + let sshport: Int? + // Environment variable + let environment: String? + let environmentvalue: String? + let checkforerrorinrsyncoutput: Int? + // Confirm execute + let confirmexecute: Int? + + enum CodingKeys: String, CodingKey { + case rsyncversion3 + case addsummarylogrecord + case logtofile + case monitornetworkconnection + case localrsyncpath + case pathforrestore + case marknumberofdayssince + case sshkeypathandidentityfile + case sshport + case environment + case environmentvalue + case checkforerrorinrsyncoutput + case confirmexecute + } + + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + rsyncversion3 = try values.decodeIfPresent(Int.self, forKey: .rsyncversion3) + addsummarylogrecord = try values.decodeIfPresent(Int.self, forKey: .addsummarylogrecord) + logtofile = try values.decodeIfPresent(Int.self, forKey: .logtofile) + monitornetworkconnection = try values.decodeIfPresent(Int.self, forKey: .monitornetworkconnection) + localrsyncpath = try values.decodeIfPresent(String.self, forKey: .localrsyncpath) + pathforrestore = try values.decodeIfPresent(String.self, forKey: .pathforrestore) + marknumberofdayssince = try values.decodeIfPresent(String.self, forKey: .marknumberofdayssince) + sshkeypathandidentityfile = try values.decodeIfPresent(String.self, forKey: .sshkeypathandidentityfile) + sshport = try values.decodeIfPresent(Int.self, forKey: .sshport) + environment = try values.decodeIfPresent(String.self, forKey: .environment) + environmentvalue = try values.decodeIfPresent(String.self, forKey: .environmentvalue) + checkforerrorinrsyncoutput = try values.decodeIfPresent(Int.self, forKey: .checkforerrorinrsyncoutput) + confirmexecute = try values.decodeIfPresent(Int.self, forKey: .confirmexecute) + } +} diff --git a/Tests/SSHCreateKeyTests/DecodeTestdata.swift b/Tests/SSHCreateKeyTests/DecodeTestdata.swift new file mode 100644 index 0000000..2e2abb0 --- /dev/null +++ b/Tests/SSHCreateKeyTests/DecodeTestdata.swift @@ -0,0 +1,99 @@ +// +// DecodeTestdata.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +struct DecodeTestdata: Codable { + let backupID: String? + let dateRun: String? + let hiddenID: Int? + let localCatalog: String? + let offsiteCatalog: String? + let offsiteServer: String? + let offsiteUsername: String? + let parameter1: String? + let parameter10: String? + let parameter11: String? + let parameter12: String? + let parameter13: String? + let parameter14: String? + let parameter2: String? + let parameter3: String? + let parameter4: String? + let parameter5: String? + let parameter6: String? + let parameter8: String? + let parameter9: String? + let rsyncdaemon: Int? + let sshkeypathandidentityfile: String? + let sshport: Int? + let task: String? + let snapdayoffweek: String? + let snaplast: Int? + let snapshotnum: Int? + + enum CodingKeys: String, CodingKey { + case backupID + case dateRun + case hiddenID + case localCatalog + case offsiteCatalog + case offsiteServer + case offsiteUsername + case parameter1 + case parameter10 + case parameter11 + case parameter12 + case parameter13 + case parameter14 + case parameter2 + case parameter3 + case parameter4 + case parameter5 + case parameter6 + case parameter8 + case parameter9 + case rsyncdaemon + case sshkeypathandidentityfile + case sshport + case task + case snapdayoffweek + case snaplast + case snapshotnum + } + + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + backupID = try values.decodeIfPresent(String.self, forKey: .backupID) + dateRun = try values.decodeIfPresent(String.self, forKey: .dateRun) + hiddenID = try values.decodeIfPresent(Int.self, forKey: .hiddenID) + localCatalog = try values.decodeIfPresent(String.self, forKey: .localCatalog) + offsiteCatalog = try values.decodeIfPresent(String.self, forKey: .offsiteCatalog) + offsiteServer = try values.decodeIfPresent(String.self, forKey: .offsiteServer) + offsiteUsername = try values.decodeIfPresent(String.self, forKey: .offsiteUsername) + parameter1 = try values.decodeIfPresent(String.self, forKey: .parameter1) + parameter10 = try values.decodeIfPresent(String.self, forKey: .parameter10) + parameter11 = try values.decodeIfPresent(String.self, forKey: .parameter11) + parameter12 = try values.decodeIfPresent(String.self, forKey: .parameter12) + parameter13 = try values.decodeIfPresent(String.self, forKey: .parameter13) + parameter14 = try values.decodeIfPresent(String.self, forKey: .parameter14) + parameter2 = try values.decodeIfPresent(String.self, forKey: .parameter2) + parameter3 = try values.decodeIfPresent(String.self, forKey: .parameter3) + parameter4 = try values.decodeIfPresent(String.self, forKey: .parameter4) + parameter5 = try values.decodeIfPresent(String.self, forKey: .parameter5) + parameter6 = try values.decodeIfPresent(String.self, forKey: .parameter6) + parameter8 = try values.decodeIfPresent(String.self, forKey: .parameter8) + parameter9 = try values.decodeIfPresent(String.self, forKey: .parameter9) + rsyncdaemon = try values.decodeIfPresent(Int.self, forKey: .rsyncdaemon) + sshkeypathandidentityfile = try values.decodeIfPresent(String.self, forKey: .sshkeypathandidentityfile) + sshport = try values.decodeIfPresent(Int.self, forKey: .sshport) + task = try values.decodeIfPresent(String.self, forKey: .task) + snapdayoffweek = try values.decodeIfPresent(String.self, forKey: .snapdayoffweek) + snaplast = try values.decodeIfPresent(Int.self, forKey: .snaplast) + snapshotnum = try values.decodeIfPresent(Int.self, forKey: .snapshotnum) + } +} diff --git a/Tests/SSHCreateKeyTests/ReadTestdataFromGitHub.swift b/Tests/SSHCreateKeyTests/ReadTestdataFromGitHub.swift new file mode 100644 index 0000000..99510ea --- /dev/null +++ b/Tests/SSHCreateKeyTests/ReadTestdataFromGitHub.swift @@ -0,0 +1,40 @@ +// +// ReadTestdataFromGitHub.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +final class ReadTestdataFromGitHub { + var testconfigurations = [TestSynchronizeConfiguration]() + + func getdata() async { + let testdata = TestdataFromGitHub() + // Load user configuration + do { + if let userconfig = try await testdata.getrsyncuiconfigbyURL() { + await TestUserConfiguration(userconfig) + print("ReadTestdataFromGitHub: loading userconfiguration COMPLETED)") + } + + } catch { + print("ReadTestdataFromGitHub: loading userconfiguration FAILED)") + } + // Load data + do { + if let testdata = try await testdata.gettestdatabyURL() { + testconfigurations.removeAll() + for i in 0 ..< testdata.count { + var configuration = TestSynchronizeConfiguration(testdata[i]) + configuration.profile = "test" + testconfigurations.append(configuration) + } + print("ReadTestdataFromGitHub: loading data COMPLETED)") + } + } catch { + print("ReadTestdataFromGitHub: loading data FAILED)") + } + } +} diff --git a/Tests/SSHCreateKeyTests/SSHCreateKeyTests.swift b/Tests/SSHCreateKeyTests/SSHCreateKeyTests.swift index d3823af..adaa4b3 100644 --- a/Tests/SSHCreateKeyTests/SSHCreateKeyTests.swift +++ b/Tests/SSHCreateKeyTests/SSHCreateKeyTests.swift @@ -1,6 +1,27 @@ import Testing @testable import SSHCreateKey -@Test func example() async throws { - // Write your test here and use APIs like `#expect(...)` to check expected conditions. +@Suite final class TestCreateSSHkeys { + var testconfigurations: [TestSynchronizeConfiguration]? + + @Test func LodaDataCreateSSHKeys() async { + let loadtestdata = ReadTestdataFromGitHub() + await loadtestdata.getdata() + testconfigurations = loadtestdata.testconfigurations + if let testconfigurations { + // Test for one configuration only, config nr 0 + guard testconfigurations.count > 0 else { return } + let config = testconfigurations[0] + let createsshkeys = await SSHCreateKey(sharedsshport: String(TestSharedReference.shared.sshport ?? -1), + sharedsshkeypathandidentityfile: TestSharedReference.shared.sshkeypathandidentityfile + ) + + let arg3 = await createsshkeys.keypathonly + print(arg3 ?? "") + let arg4 = await createsshkeys.identityfile + print(arg4 ?? "") + let arg5 = await createsshkeys.userHomeDirectoryPath + print(arg5 ?? "") + } + } } diff --git a/Tests/SSHCreateKeyTests/TestSharedReference.swift b/Tests/SSHCreateKeyTests/TestSharedReference.swift new file mode 100644 index 0000000..7f4ded0 --- /dev/null +++ b/Tests/SSHCreateKeyTests/TestSharedReference.swift @@ -0,0 +1,67 @@ +// +// TestSharedReference.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +@MainActor +final class TestSharedReference { + @MainActor static let shared = TestSharedReference() + private init() { + synctasks = Set<String>() + synctasks = [synchronize, snapshot, syncremote] + } + + var settingsischanged: Bool = false + var rsyncversion3: Bool = true + var localrsyncpath: String? + var norsync: Bool = false + var pathforrestore: String? + var addsummarylogrecord: Bool = true + var logtofile: Bool = false + var marknumberofdayssince: Int = 5 + var environment: String? + var environmentvalue: String? + var sshport: Int? + var sshkeypathandidentityfile: String? + var checkforerrorinrsyncoutput: Bool = false + var monitornetworkconnection: Bool = false + var confirmexecute: Bool = false + var URLnewVersion: String? + let rsync: String = "rsync" + let usrbin: String = "/usr/bin" + let usrlocalbin: String = "/usr/local/bin" + let usrlocalbinarm: String = "/opt/homebrew/bin" + var macosarm: Bool = true + // RsyncUI config files and path + let configpath: String = "/.rsyncosx/" + let logname: String = "rsyncui.txt" + // Userconfiguration json file + let userconfigjson: String = "rsyncuiconfig.json" + // String tasks + let synchronize: String = "synchronize" + let snapshot: String = "snapshot" + let syncremote: String = "syncremote" + var synctasks: Set<String> + // rsync short version + var rsyncversionshort: String? + // filsize logfile warning + let logfilesize: Int = 100_000 + // Mac serialnumer + var macserialnumber: String? + // True if menuapp is running + // var menuappisrunning: Bool = false + // Reference to the active process + var process: Process? + // JSON names + let filenamelogrecordsjson = "logrecords.json" + let fileconfigurationsjson = "configurations.json" + // Object for propogate errors to views + // var errorobject: AlertError? + // Used when starting up RsyncUI + // Default profile + let defaultprofile = "Testprofile" +} diff --git a/Tests/SSHCreateKeyTests/TestSynchronizeConfiguration.swift b/Tests/SSHCreateKeyTests/TestSynchronizeConfiguration.swift new file mode 100644 index 0000000..9ef8a49 --- /dev/null +++ b/Tests/SSHCreateKeyTests/TestSynchronizeConfiguration.swift @@ -0,0 +1,140 @@ +// +// TestSynchronizeConfiguration.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +struct TestSynchronizeConfiguration: Identifiable, Codable { + var id = UUID() + var hiddenID: Int + var task: String + var localCatalog: String + var offsiteCatalog: String + var offsiteUsername: String + var parameter1: String + var parameter2: String + var parameter3: String + var parameter4: String + var parameter5: String + var parameter6: String + var offsiteServer: String + var backupID: String + var dateRun: String? + var snapshotnum: Int? + // parameters choosed by user + var parameter8: String? + var parameter9: String? + var parameter10: String? + var parameter11: String? + var parameter12: String? + var parameter13: String? + var parameter14: String? + var rsyncdaemon: Int? + // SSH parameters + var sshport: Int? + var sshkeypathandidentityfile: String? + + var profile: String? + // Snapshots, day to save and last = 1 or every last=0 + var snapdayoffweek: String? + var snaplast: Int? + + // Used when reading JSON data from store + // see in ReadConfigurationJSON + init(_ data: DecodeTestdata) { + backupID = data.backupID ?? "" + hiddenID = data.hiddenID ?? -1 + localCatalog = data.localCatalog ?? "" + offsiteCatalog = data.offsiteCatalog ?? "" + offsiteServer = data.offsiteServer ?? "" + offsiteUsername = data.offsiteUsername ?? "" + parameter1 = data.parameter1 ?? "" + parameter10 = data.parameter10 + parameter11 = data.parameter11 + parameter12 = data.parameter12 + parameter13 = data.parameter13 + parameter14 = data.parameter14 + parameter2 = data.parameter2 ?? "" + parameter3 = data.parameter3 ?? "" + parameter4 = data.parameter4 ?? "" + parameter5 = data.parameter5 ?? "" + parameter6 = data.parameter6 ?? "" + parameter8 = data.parameter8 + parameter9 = data.parameter9 + rsyncdaemon = data.rsyncdaemon + sshkeypathandidentityfile = data.sshkeypathandidentityfile + sshport = data.sshport ?? -1 + task = data.task ?? "" + // For snapshots + if let snapshotnum = data.snapshotnum { + self.snapshotnum = snapshotnum + snapdayoffweek = data.snapdayoffweek ?? TestStringDayofweek.Sunday.rawValue + snaplast = data.snaplast ?? 1 + } + // Last run of task + dateRun = data.dateRun + } +} + +extension TestSynchronizeConfiguration: Hashable, Equatable { + static func == (lhs: TestSynchronizeConfiguration, rhs: TestSynchronizeConfiguration) -> Bool { + lhs.localCatalog == rhs.localCatalog && + lhs.offsiteCatalog == rhs.offsiteCatalog && + lhs.offsiteUsername == rhs.offsiteUsername && + lhs.offsiteServer == rhs.offsiteServer && + lhs.hiddenID == rhs.hiddenID && + lhs.task == rhs.task && + lhs.parameter1 == rhs.parameter1 && + lhs.parameter2 == rhs.parameter2 && + lhs.parameter3 == rhs.parameter3 && + lhs.parameter4 == rhs.parameter4 && + lhs.parameter5 == rhs.parameter5 && + lhs.parameter6 == rhs.parameter6 && + lhs.parameter8 == rhs.parameter8 && + lhs.parameter9 == rhs.parameter9 && + lhs.parameter10 == rhs.parameter10 && + lhs.parameter11 == rhs.parameter11 && + lhs.parameter12 == rhs.parameter12 && + lhs.parameter13 == rhs.parameter13 && + lhs.parameter14 == rhs.parameter14 && + lhs.dateRun == rhs.dateRun + } + + func hash(into hasher: inout Hasher) { + hasher.combine(localCatalog) + hasher.combine(offsiteUsername) + hasher.combine(offsiteServer) + hasher.combine(String(hiddenID)) + hasher.combine(task) + hasher.combine(parameter1) + hasher.combine(parameter2) + hasher.combine(parameter3) + hasher.combine(parameter4) + hasher.combine(parameter5) + hasher.combine(parameter6) + hasher.combine(parameter8) + hasher.combine(parameter9) + hasher.combine(parameter10) + hasher.combine(parameter11) + hasher.combine(parameter12) + hasher.combine(parameter13) + hasher.combine(parameter14) + hasher.combine(dateRun) + } +} + +enum TestStringDayofweek: String, CaseIterable, Identifiable, CustomStringConvertible { + case Monday + case Tuesday + case Wednesday + case Thursday + case Friday + case Saturday + case Sunday + + var id: String { rawValue } + var description: String { rawValue.localizedLowercase } +} diff --git a/Tests/SSHCreateKeyTests/TestUserConfiguration.swift b/Tests/SSHCreateKeyTests/TestUserConfiguration.swift new file mode 100644 index 0000000..85cb981 --- /dev/null +++ b/Tests/SSHCreateKeyTests/TestUserConfiguration.swift @@ -0,0 +1,172 @@ +// +// TestUserConfiguration.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +struct TestUserConfiguration: Codable { + var rsyncversion3: Int = -1 + // Detailed logging + var addsummarylogrecord: Int = 1 + // Logging to logfile + var logtofile: Int = 1 + // Montor network connection + var monitornetworkconnection: Int = -1 + // local path for rsync + var localrsyncpath: String? + // temporary path for restore + var pathforrestore: String? + // days for mark days since last synchronize + var marknumberofdayssince: String = "5" + // Global ssh keypath and port + var sshkeypathandidentityfile: String? + var sshport: Int? + // Environment variable + var environment: String? + var environmentvalue: String? + // Check for error in output from rsync + var checkforerrorinrsyncoutput: Int = -1 + // Automatic execution + var confirmexecute: Int? + + @MainActor private func setuserconfigdata() { + if rsyncversion3 == 1 { + TestSharedReference.shared.rsyncversion3 = true + } else { + TestSharedReference.shared.rsyncversion3 = false + } + if addsummarylogrecord == 1 { + TestSharedReference.shared.addsummarylogrecord = true + } else { + TestSharedReference.shared.addsummarylogrecord = false + } + if logtofile == 1 { + TestSharedReference.shared.logtofile = true + } else { + TestSharedReference.shared.logtofile = false + } + if monitornetworkconnection == 1 { + TestSharedReference.shared.monitornetworkconnection = true + } else { + TestSharedReference.shared.monitornetworkconnection = false + } + if localrsyncpath != nil { + TestSharedReference.shared.localrsyncpath = localrsyncpath + } else { + TestSharedReference.shared.localrsyncpath = nil + } + if pathforrestore != nil { + TestSharedReference.shared.pathforrestore = pathforrestore + } else { + TestSharedReference.shared.pathforrestore = nil + } + if Int(marknumberofdayssince) ?? 0 > 0 { + TestSharedReference.shared.marknumberofdayssince = Int(marknumberofdayssince) ?? 0 + } + if sshkeypathandidentityfile != nil { + TestSharedReference.shared.sshkeypathandidentityfile = sshkeypathandidentityfile + } + if sshport != nil { + TestSharedReference.shared.sshport = sshport + } + if environment != nil { + TestSharedReference.shared.environment = environment + } + if environmentvalue != nil { + TestSharedReference.shared.environmentvalue = environmentvalue + } + if checkforerrorinrsyncoutput == 1 { + TestSharedReference.shared.checkforerrorinrsyncoutput = true + } else { + TestSharedReference.shared.checkforerrorinrsyncoutput = false + } + if confirmexecute == 1 { + TestSharedReference.shared.confirmexecute = true + } else { + TestSharedReference.shared.confirmexecute = false + } + } + + // Used when reading JSON data from store + @discardableResult + @MainActor init(_ data: DecodeTestUserConfiguration) { + rsyncversion3 = data.rsyncversion3 ?? -1 + addsummarylogrecord = data.addsummarylogrecord ?? 1 + logtofile = data.logtofile ?? 0 + monitornetworkconnection = data.monitornetworkconnection ?? -1 + localrsyncpath = data.localrsyncpath + pathforrestore = data.pathforrestore + marknumberofdayssince = data.marknumberofdayssince ?? "5" + sshkeypathandidentityfile = data.sshkeypathandidentityfile + sshport = data.sshport + environment = data.environment + environmentvalue = data.environmentvalue + checkforerrorinrsyncoutput = data.checkforerrorinrsyncoutput ?? -1 + confirmexecute = data.confirmexecute ?? -1 + // Set user configdata read from permanent store + setuserconfigdata() + } + + // Default values user configuration + @discardableResult + @MainActor init() { + if TestSharedReference.shared.rsyncversion3 { + rsyncversion3 = 1 + } else { + rsyncversion3 = -1 + } + if TestSharedReference.shared.addsummarylogrecord { + addsummarylogrecord = 1 + } else { + addsummarylogrecord = -1 + } + if TestSharedReference.shared.logtofile { + logtofile = 1 + } else { + logtofile = -1 + } + if TestSharedReference.shared.monitornetworkconnection { + monitornetworkconnection = 1 + } else { + monitornetworkconnection = -1 + } + if TestSharedReference.shared.localrsyncpath != nil { + localrsyncpath = TestSharedReference.shared.localrsyncpath + } else { + localrsyncpath = nil + } + if TestSharedReference.shared.pathforrestore != nil { + pathforrestore = TestSharedReference.shared.pathforrestore + } else { + pathforrestore = nil + } + marknumberofdayssince = String(TestSharedReference.shared.marknumberofdayssince) + if TestSharedReference.shared.sshkeypathandidentityfile != nil { + sshkeypathandidentityfile = TestSharedReference.shared.sshkeypathandidentityfile + } + if TestSharedReference.shared.sshport != nil { + sshport = TestSharedReference.shared.sshport + } + if TestSharedReference.shared.environment != nil { + environment = TestSharedReference.shared.environment + } + if TestSharedReference.shared.environmentvalue != nil { + environmentvalue = TestSharedReference.shared.environmentvalue + } + if TestSharedReference.shared.checkforerrorinrsyncoutput == true { + checkforerrorinrsyncoutput = 1 + } else { + checkforerrorinrsyncoutput = -1 + } + if TestSharedReference.shared.confirmexecute == true { + confirmexecute = 1 + } else { + confirmexecute = -1 + } + } +} + +// swiftlint:enable cyclomatic_complexity function_body_length diff --git a/Tests/SSHCreateKeyTests/TestdataFromGitHub.swift b/Tests/SSHCreateKeyTests/TestdataFromGitHub.swift new file mode 100644 index 0000000..9b4696f --- /dev/null +++ b/Tests/SSHCreateKeyTests/TestdataFromGitHub.swift @@ -0,0 +1,41 @@ +// +// TestdataFromGitHub.swift +// RsyncArguments +// +// Created by Thomas Evensen on 05/08/2024. +// + +import Foundation + +struct TestdataFromGitHub { + let urlSession = URLSession.shared + let jsonDecoder = JSONDecoder() + + private var urlJSON: String = "https://raw.githubusercontent.com/rsyncOSX/RsyncArguments/master/Testdata/configurations.json" + + func gettestdatabyURL() async throws -> [DecodeTestdata]? { + if let url = URL(string: urlJSON) { + let (data, _) = try await urlSession.gettestdata(for: url) + return try jsonDecoder.decode([DecodeTestdata].self, from: data) + } else { + return nil + } + } + + private var urlJSONuiconfig: String = "https://raw.githubusercontent.com/rsyncOSX/RsyncArguments/master/Testdata/rsyncuiconfig.json" + + func getrsyncuiconfigbyURL() async throws -> DecodeTestUserConfiguration? { + if let url = URL(string: urlJSONuiconfig) { + let (data, _) = try await urlSession.gettestdata(for: url) + return try jsonDecoder.decode(DecodeTestUserConfiguration.self, from: data) + } else { + return nil + } + } +} + +public extension URLSession { + func gettestdata(for url: URL) async throws -> (Data, URLResponse) { + try await data(from: url) + } +} -- GitLab