diff --git a/.gitignore b/.gitignore index 347a4a0..0ee7fca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store .build +.idea/ diff --git a/NMSSH/NMSSH-iOS.xcodeproj/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist b/NMSSH/NMSSH-iOS.xcodeproj/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist index a4dff35..f3f97b2 100644 --- a/NMSSH/NMSSH-iOS.xcodeproj/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/NMSSH/NMSSH-iOS.xcodeproj/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist @@ -25,12 +25,12 @@ 18A0964E17D6A8C4008B76FB primary - + 18A0965D17D6A97C008B76FB primary - + diff --git a/SCP.xcodeproj/project.pbxproj b/SCP.xcodeproj/project.pbxproj index 7fa125b..caa2809 100644 --- a/SCP.xcodeproj/project.pbxproj +++ b/SCP.xcodeproj/project.pbxproj @@ -224,6 +224,7 @@ 6BC17E5220774D6300E2A999 /* Frameworks */, 6BC17E5320774D6300E2A999 /* Resources */, 6BC17E7E2077602000E2A999 /* Embed Frameworks */, + 6B9CEB9B208DF296006E2332 /* ShellScript */, ); buildRules = ( ); @@ -335,6 +336,22 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 6B9CEB9B208DF296006E2332 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "buildNumber=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"$INFOPLIST_FILE\")\nbuildNumber=$(($buildNumber + 1))\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $buildNumber\" \"$INFOPLIST_FILE\""; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 6BC17E5120774D6300E2A999 /* Sources */ = { isa = PBXSourcesBuildPhase; diff --git a/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/UserInterfaceState.xcuserstate b/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/UserInterfaceState.xcuserstate index 83c9f3f..94e21c1 100644 Binary files a/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/UserInterfaceState.xcuserstate and b/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist b/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ee3458d --- /dev/null +++ b/SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/SCP/AddServerViewController.swift b/SCP/AddServerViewController.swift index 015c86b..56a3c38 100644 --- a/SCP/AddServerViewController.swift +++ b/SCP/AddServerViewController.swift @@ -9,80 +9,80 @@ import Eureka class AddServerViewController: FormViewController { - - var serverForm:Form? = nil - + + var serverForm: Form? = nil + override func viewDidLoad() { - super.viewDidLoad() - + super.viewDidLoad() + serverForm = form +++ Section() - <<< NameRow(){ row in - row.title = "Name" - row.placeholder = "Name" - row.tag = "name" - } - <<< TextRow(){ - $0.title = "Host" - $0.placeholder = "URL or IP of Host" - $0.tag = "host" - } - <<< IntRow(){ - $0.title = "Port" - $0.placeholder = "Defaults to 22" - $0.tag = "port" - } - <<< TextRow(){ - $0.title = "Username" - $0.placeholder = "Defaults to root" - $0.tag = "user" - } - <<< PasswordRow(){ - $0.title = "Password" - $0.placeholder = "password" - $0.tag = "pass" - } - +++ Section() - <<< ButtonRow(){ - $0.title = "Add Server" - }.onCellSelection { cell, row in - let keychain = Keychain() - do { - let nameRow: NameRow? = self.serverForm?.rowBy(tag: "name") - let portRow: IntRow? = self.serverForm?.rowBy(tag: "port") - let userRow: TextRow? = self.serverForm?.rowBy(tag: "user") - let hostRow: TextRow? = self.serverForm?.rowBy(tag: "host") - let passRow: PasswordRow? = self.serverForm?.rowBy(tag: "pass") - - let name = nameRow?.value != nil ? nameRow?.value : "SSH Server" - let port = portRow?.value != nil ? portRow?.value : 22 - let user = userRow?.value != nil ? userRow?.value : "root" - - let server = SSHServer(name: name!, - host: hostRow!.value!, - port: port!, - user: user!, - pass: passRow!.value!) + <<< NameRow() { row in + row.title = "Name" + row.placeholder = "Name" + row.tag = "name" + } + <<< TextRow() { + $0.title = "Host" + $0.placeholder = "URL or IP of Host" + $0.tag = "host" + } + <<< IntRow() { + $0.title = "Port" + $0.placeholder = "Defaults to 22" + $0.tag = "port" + } + <<< TextRow() { + $0.title = "Username" + $0.placeholder = "Defaults to root" + $0.tag = "user" + } + <<< PasswordRow() { + $0.title = "Password" + $0.placeholder = "password" + $0.tag = "pass" + } + +++ Section() + <<< ButtonRow() { + $0.title = "Add Server" + }.onCellSelection { cell, row in + let keychain = Keychain() + do { + let nameRow: NameRow? = self.serverForm?.rowBy(tag: "name") + let portRow: IntRow? = self.serverForm?.rowBy(tag: "port") + let userRow: TextRow? = self.serverForm?.rowBy(tag: "user") + let hostRow: TextRow? = self.serverForm?.rowBy(tag: "host") + let passRow: PasswordRow? = self.serverForm?.rowBy(tag: "pass") + + let name = nameRow?.value != nil ? nameRow?.value : "SSH Server" + let port = portRow?.value != nil ? portRow?.value : 22 + let user = userRow?.value != nil ? userRow?.value : "root" - let jsonEncoder = JSONEncoder() - let jsonData = try jsonEncoder.encode(server) - let jsonString = String(data: jsonData, encoding: .utf8) - - try keychain.set(jsonString!, key: UUID().uuidString) - - _ = self.navigationController?.popViewController(animated: true) - } catch let error { - print("error: \(error)") - } - } + let server = SSHServer(name: name!, + host: hostRow!.value!, + port: port!, + user: user!, + pass: passRow!.value!) + + let jsonEncoder = JSONEncoder() + let jsonData = try jsonEncoder.encode(server) + let jsonString = String(data: jsonData, encoding: .utf8) + + try keychain.set(jsonString!, key: UUID().uuidString) + + _ = self.navigationController?.popViewController(animated: true) + } catch let error { + print("error: \(error)") + } + } } - + override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - + + /* // MARK: - Navigation @@ -92,5 +92,5 @@ class AddServerViewController: FormViewController { // Pass the selected object to the new view controller. } */ - + } diff --git a/SCP/AppDelegate.swift b/SCP/AppDelegate.swift index 332968e..13f30d5 100644 --- a/SCP/AppDelegate.swift +++ b/SCP/AppDelegate.swift @@ -9,17 +9,12 @@ import UIKit @UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate { +class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - let splitViewController = window!.rootViewController as! UISplitViewController - let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController - navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem - splitViewController.delegate = self return true } @@ -45,17 +40,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - // MARK: - Split view - - func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool { - guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false } - guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false } - if topAsDetailController.detailItem == nil { - // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. - return true - } - return false - } - } diff --git a/SCP/Base.lproj/Main.storyboard b/SCP/Base.lproj/Main.storyboard index 5debda8..9fd01b5 100644 --- a/SCP/Base.lproj/Main.storyboard +++ b/SCP/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -85,6 +85,7 @@ + @@ -131,20 +132,6 @@ - - - - - - - - - - - - - - @@ -178,9 +165,6 @@ - - - @@ -194,6 +178,7 @@ + @@ -232,7 +217,4 @@ - - - diff --git a/SCP/DetailViewController.swift b/SCP/DetailViewController.swift index 5c89794..aa0448e 100644 --- a/SCP/DetailViewController.swift +++ b/SCP/DetailViewController.swift @@ -8,99 +8,130 @@ import UIKit -class DetailViewController: UIViewController,UIPopoverPresentationControllerDelegate { - +class DetailViewController: UIViewController, UIPopoverPresentationControllerDelegate { + @IBOutlet var leftTable: UITableView? @IBOutlet var rightTable: UITableView? - - var leftServer:SSHServerTableViewController? = nil - var rightServer:SSHServerTableViewController? = nil - - func configureView() { - // Update the user interface for the detail item. + + var leftServer: SSHServerTableViewController? = nil + var rightServer: SSHServerTableViewController? = nil + + func configureView() { + + if let viewState = UserDefaults.standard.object(forKey: detailItemUUID + "_selected_view") as? Int { + DispatchQueue.main.async { + if (viewState == 1) { + self.showLeft() + } else if (viewState == 2) { + self.showBoth() + } else if (viewState == 3) { + self.showRigh() + } + } + } + if let detail = detailItem { do { let jsonDecoder = JSONDecoder() let server = try jsonDecoder.decode(SSHServer.self, from: detail.data(using: .utf8)!) - + + self.title = server.name + leftServer = SSHServerTableViewController.init(nibName: nil, bundle: nil) rightServer = SSHServerTableViewController.init(nibName: nil, bundle: nil) - + leftServer?.isLeft = true - + rightServer?.isLeft = false + leftServer?.tableView = leftTable rightServer?.tableView = rightTable - + leftServer?.SSHServer = server rightServer?.SSHServer = server - + leftServer?.presenter = self.presenter rightServer?.presenter = self.presenter - + leftServer?.sideListener = rightServer?.sideReceived rightServer?.sideListener = leftServer?.sideReceived - + leftServer?.executionListener = rightServer?.handleAfterExecution rightServer?.executionListener = leftServer?.handleAfterExecution - + + leftServer?.serverUUID = detailItemUUID + rightServer?.serverUUID = detailItemUUID + leftServer?.start(); rightServer?.start(); - + } catch let error { print("error: \(error)") } } } - + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - + leftServer?.stop() rightServer?.stop() } - + override func viewDidLoad() { super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. - configureView() - + + DispatchQueue.global(qos: .userInteractive).async { + self.configureView() + } + for barButton in self.navigationItem.rightBarButtonItems! { - if(barButton.tag == 1) { + if (barButton.tag == 1) { barButton.setIcon(icon: .googleMaterialDesign(.borderLeft), iconSize: 30, color: .blue) - } else if(barButton.tag == 2) { + } else if (barButton.tag == 2) { barButton.setIcon(icon: .googleMaterialDesign(.borderVertical), iconSize: 30, color: .blue) - } else if(barButton.tag == 3) { + } else if (barButton.tag == 3) { barButton.setIcon(icon: .googleMaterialDesign(.borderRight), iconSize: 30, color: .blue) } } + + self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissOnDone)) + } + + @objc func dismissOnDone() { + self.dismiss(animated: true, completion: nil) } - + private func presenter(_ viewControllerToPresent: UIAlertController, animated flag: Bool, completion: (() -> Void)? = nil) { self.present(viewControllerToPresent, animated: flag, completion: completion) } - + override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - - @IBAction func showLeft(sender: UIBarButtonItem) { + + @IBAction func showLeft(sender: UIBarButtonItem? = nil) { leftTable?.isHidden = false rightTable?.isHidden = true + + UserDefaults.standard.set(1, forKey: detailItemUUID + "_selected_view") } - - @IBAction func showBoth(sender: UIBarButtonItem) { + + @IBAction func showBoth(sender: UIBarButtonItem? = nil) { leftTable?.isHidden = false rightTable?.isHidden = false + UserDefaults.standard.set(2, forKey: detailItemUUID + "_selected_view") } - - @IBAction func showRigh(sender: UIBarButtonItem) { + + @IBAction func showRigh(sender: UIBarButtonItem? = nil) { leftTable?.isHidden = true rightTable?.isHidden = false + UserDefaults.standard.set(3, forKey: detailItemUUID + "_selected_view") } - + var detailItem: String? - - + var detailItemUUID: String = "" + + } diff --git a/SCP/Info.plist b/SCP/Info.plist index b32a9e6..55c9b97 100644 --- a/SCP/Info.plist +++ b/SCP/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.1 CFBundleVersion - 19 + 33 LSRequiresIPhoneOS UILaunchStoryboardName diff --git a/SCP/Keychain.swift b/SCP/Keychain.swift index 5821748..2bf1422 100755 --- a/SCP/Keychain.swift +++ b/SCP/Keychain.swift @@ -223,19 +223,19 @@ public struct AuthenticationPolicy: OptionSet { @available(watchOS, unavailable) public static let applicationPassword = AuthenticationPolicy(rawValue: 1 << 31) - #if swift(>=2.3) +#if swift(>=2.3) public let rawValue: UInt public init(rawValue: UInt) { self.rawValue = rawValue } - #else - public let rawValue: Int +#else +public let rawValue:Int - public init(rawValue: Int) { - self.rawValue = rawValue - } - #endif +public init(rawValue:Int) { +self.rawValue = rawValue +} +#endif } public struct Attributes { @@ -392,12 +392,12 @@ public final class Keychain { return options.authenticationPrompt } - #if os(iOS) || os(OSX) +#if os(iOS) || os(OSX) @available(iOS 9.0, OSX 10.11, *) public var authenticationContext: LAContext? { return options.authenticationContext as? LAContext } - #endif +#endif fileprivate let options: Options @@ -487,7 +487,9 @@ public final class Keychain { public func attributes(_ attributes: [String: Any]) -> Keychain { var options = self.options - attributes.forEach { options.attributes.updateValue($1, forKey: $0) } + attributes.forEach { + options.attributes.updateValue($1, forKey: $0) + } return Keychain(options) } @@ -499,14 +501,14 @@ public final class Keychain { return Keychain(options) } - #if os(iOS) || os(OSX) +#if os(iOS) || os(OSX) @available(iOS 9.0, OSX 10.11, *) public func authenticationContext(_ authenticationContext: LAContext) -> Keychain { var options = self.options options.authenticationContext = authenticationContext return Keychain(options) } - #endif +#endif // MARK: @@ -515,7 +517,7 @@ public final class Keychain { } public func getString(_ key: String) throws -> String? { - guard let data = try getData(key) else { + guard let data = try getData(key) else { return nil } guard let string = String(data: data, encoding: .utf8) else { @@ -590,18 +592,18 @@ public final class Keychain { public func set(_ value: Data, key: String) throws { var query = options.query() query[AttributeAccount] = key - #if os(iOS) +#if os(iOS) if #available(iOS 9.0, *) { query[UseAuthenticationUI] = UseAuthenticationUIFail } else { query[UseNoAuthenticationUI] = kCFBooleanTrue } - #elseif os(OSX) +#elseif os(OSX) query[ReturnData] = kCFBooleanTrue if #available(OSX 10.11, *) { query[UseAuthenticationUI] = UseAuthenticationUIFail } - #endif +#endif var status = SecItemCopyMatching(query as CFDictionary, nil) switch status { @@ -615,9 +617,11 @@ public final class Keychain { throw error } - options.attributes.forEach { attributes.updateValue($1, forKey: $0) } + options.attributes.forEach { + attributes.updateValue($1, forKey: $0) + } - #if os(iOS) +#if os(iOS) if status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_8_0) { try remove(key) try set(value, key: key) @@ -627,12 +631,12 @@ public final class Keychain { throw securityError(status: status) } } - #else +#else status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary) if status != errSecSuccess { throw securityError(status: status) } - #endif +#endif case errSecItemNotFound: var (attributes, error) = options.attributes(key: key, value: value) if let error = error { @@ -640,7 +644,9 @@ public final class Keychain { throw error } - options.attributes.forEach { attributes.updateValue($1, forKey: $0) } + options.attributes.forEach { + attributes.updateValue($1, forKey: $0) + } status = SecItemAdd(attributes as CFDictionary, nil) if status != errSecSuccess { @@ -653,18 +659,22 @@ public final class Keychain { public subscript(key: String) -> String? { get { - return (try? get(key)).flatMap { $0 } + return (try? get(key)).flatMap { + $0 + } } set { if let value = newValue { do { try set(value, key: key) - } catch {} + } catch { + } } else { do { try remove(key) - } catch {} + } catch { + } } } } @@ -681,25 +691,33 @@ public final class Keychain { public subscript(data key: String) -> Data? { get { - return (try? getData(key)).flatMap { $0 } + return (try? getData(key)).flatMap { + $0 + } } set { if let value = newValue { do { try set(value, key: key) - } catch {} + } catch { + } } else { do { try remove(key) - } catch {} + } catch { + } } } } public subscript(attributes key: String) -> Attributes? { get { - return (try? get(key) { $0 }).flatMap { $0 } + return (try? get(key) { + $0 + }).flatMap { + $0 + } } } @@ -717,9 +735,9 @@ public final class Keychain { public func removeAll() throws { var query = options.query() - #if !os(iOS) && !os(watchOS) && !os(tvOS) +#if !os(iOS) && !os(watchOS) && !os(tvOS) query[MatchLimit] = MatchLimitAll - #endif +#endif let status = SecItemDelete(query as CFDictionary) if status != errSecSuccess && status != errSecItemNotFound { @@ -778,7 +796,9 @@ public final class Keychain { } public func allKeys() -> [String] { - return type(of: self).prettify(itemClass: itemClass, items: items()).compactMap { $0["key"] as? String } + return type(of: self).prettify(itemClass: itemClass, items: items()).compactMap { + $0["key"] as? String + } } public class func allItems(_ itemClass: ItemClass) -> [[String: Any]] { @@ -786,9 +806,9 @@ public final class Keychain { query[Class] = itemClass.rawValue query[MatchLimit] = MatchLimitAll query[ReturnAttributes] = kCFBooleanTrue - #if os(iOS) || os(watchOS) || os(tvOS) +#if os(iOS) || os(watchOS) || os(tvOS) query[ReturnData] = kCFBooleanTrue - #endif +#endif var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) @@ -811,9 +831,10 @@ public final class Keychain { return type(of: self).prettify(itemClass: itemClass, items: items()) } - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public func getSharedPassword(_ completion: @escaping (_ account: String?, _ password: String?, _ error: Error?) -> () = { account, password, error -> () in }) { + public func getSharedPassword(_ completion: @escaping (_ account: String?, _ password: String?, _ error: Error?) -> () = { account, password, error -> () in + }) { if let domain = server.host { type(of: self).requestSharedWebCredential(domain: domain, account: nil) { (credentials, error) -> () in if let credential = credentials.first { @@ -829,11 +850,12 @@ public final class Keychain { completion(nil, nil, error) } } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public func getSharedPassword(_ account: String, completion: @escaping (_ password: String?, _ error: Error?) -> () = { password, error -> () in }) { + public func getSharedPassword(_ account: String, completion: @escaping (_ password: String?, _ error: Error?) -> () = { password, error -> () in + }) { if let domain = server.host { type(of: self).requestSharedWebCredential(domain: domain, account: account) { (credentials, error) -> () in if let credential = credentials.first { @@ -851,18 +873,20 @@ public final class Keychain { completion(nil, error) } } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public func setSharedPassword(_ password: String, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) { + public func setSharedPassword(_ password: String, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in + }) { setSharedPassword(password as String?, account: account, completion: completion) } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - fileprivate func setSharedPassword(_ password: String?, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) { + fileprivate func setSharedPassword(_ password: String?, account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in + }) { if let domain = server.host { SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error -> () in if let error = error { @@ -876,37 +900,41 @@ public final class Keychain { completion(error) } } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public func removeSharedPassword(_ account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in }) { + public func removeSharedPassword(_ account: String, completion: @escaping (_ error: Error?) -> () = { e -> () in + }) { setSharedPassword(nil, account: account, completion: completion) } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public class func requestSharedWebCredential(_ completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) { + public class func requestSharedWebCredential(_ completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in + }) { requestSharedWebCredential(domain: nil, account: nil, completion: completion) } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public class func requestSharedWebCredential(domain: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) { + public class func requestSharedWebCredential(domain: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in + }) { requestSharedWebCredential(domain: domain, account: nil, completion: completion) } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) - public class func requestSharedWebCredential(domain: String, account: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in }) { + public class func requestSharedWebCredential(domain: String, account: String, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> () = { credentials, error -> () in + }) { requestSharedWebCredential(domain: Optional(domain), account: Optional(account)!, completion: completion) } - #endif +#endif - #if os(iOS) +#if os(iOS) @available(iOS 8.0, *) fileprivate class func requestSharedWebCredential(domain: String?, account: String?, completion: @escaping (_ credentials: [[String: String]], _ error: Error?) -> ()) { SecRequestSharedWebCredential(domain as CFString?, account as CFString?) { (credentials, error) -> () in @@ -939,9 +967,9 @@ public final class Keychain { } } } - #endif +#endif - #if os(iOS) +#if os(iOS) /** @abstract Returns a randomly generated password. @return String password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present. @@ -950,7 +978,7 @@ public final class Keychain { public class func generatePassword() -> String { return SecCreateSharedWebCredentialPassword()! as String } - #endif +#endif // MARK: @@ -958,9 +986,9 @@ public final class Keychain { var query = options.query() query[MatchLimit] = MatchLimitAll query[ReturnAttributes] = kCFBooleanTrue - #if os(iOS) || os(watchOS) || os(tvOS) +#if os(iOS) || os(watchOS) || os(tvOS) query[ReturnData] = kCFBooleanTrue - #endif +#endif var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) @@ -1015,7 +1043,7 @@ public final class Keychain { if let data = attributes[ValueData] as? Data { if let text = String(data: data, encoding: .utf8) { item["value"] = text - } else { + } else { item["value"] = data } } @@ -1188,11 +1216,11 @@ extension Options { case .genericPassword: query[AttributeService] = service // Access group is not supported on any simulators. - #if (!arch(i386) && !arch(x86_64)) || (!os(iOS) && !os(watchOS) && !os(tvOS)) +#if (!arch(i386) && !arch(x86_64)) || (!os(iOS) && !os(watchOS) && !os(tvOS)) if let accessGroup = self.accessGroup { query[AttributeAccessGroup] = accessGroup } - #endif +#endif case .internetPassword: query[AttributeServer] = server.host query[AttributePort] = server.port @@ -1206,13 +1234,13 @@ extension Options { } } - #if !os(watchOS) +#if !os(watchOS) if #available(iOS 9.0, OSX 10.11, *) { if authenticationContext != nil { query[UseAuthenticationContext] = authenticationContext } } - #endif +#endif return query } @@ -1674,409 +1702,409 @@ extension CFError { } public enum Status: OSStatus, Error { - case success = 0 - case unimplemented = -4 - case diskFull = -34 - case io = -36 - case opWr = -49 - case param = -50 - case wrPerm = -61 - case allocate = -108 - case userCanceled = -128 - case badReq = -909 - case internalComponent = -2070 - case notAvailable = -25291 - case readOnly = -25292 - case authFailed = -25293 - case noSuchKeychain = -25294 - case invalidKeychain = -25295 - case duplicateKeychain = -25296 - case duplicateCallback = -25297 - case invalidCallback = -25298 - case duplicateItem = -25299 - case itemNotFound = -25300 - case bufferTooSmall = -25301 - case dataTooLarge = -25302 - case noSuchAttr = -25303 - case invalidItemRef = -25304 - case invalidSearchRef = -25305 - case noSuchClass = -25306 - case noDefaultKeychain = -25307 - case interactionNotAllowed = -25308 - case readOnlyAttr = -25309 - case wrongSecVersion = -25310 - case keySizeNotAllowed = -25311 - case noStorageModule = -25312 - case noCertificateModule = -25313 - case noPolicyModule = -25314 - case interactionRequired = -25315 - case dataNotAvailable = -25316 - case dataNotModifiable = -25317 - case createChainFailed = -25318 - case invalidPrefsDomain = -25319 - case inDarkWake = -25320 - case aclNotSimple = -25240 - case policyNotFound = -25241 - case invalidTrustSetting = -25242 - case noAccessForItem = -25243 - case invalidOwnerEdit = -25244 - case trustNotAvailable = -25245 - case unsupportedFormat = -25256 - case unknownFormat = -25257 - case keyIsSensitive = -25258 - case multiplePrivKeys = -25259 - case passphraseRequired = -25260 - case invalidPasswordRef = -25261 - case invalidTrustSettings = -25262 - case noTrustSettings = -25263 - case pkcs12VerifyFailure = -25264 - case invalidCertificate = -26265 - case notSigner = -26267 - case policyDenied = -26270 - case invalidKey = -26274 - case decode = -26275 - case `internal` = -26276 - case unsupportedAlgorithm = -26268 - case unsupportedOperation = -26271 - case unsupportedPadding = -26273 - case itemInvalidKey = -34000 - case itemInvalidKeyType = -34001 - case itemInvalidValue = -34002 - case itemClassMissing = -34003 - case itemMatchUnsupported = -34004 - case useItemListUnsupported = -34005 - case useKeychainUnsupported = -34006 - case useKeychainListUnsupported = -34007 - case returnDataUnsupported = -34008 - case returnAttributesUnsupported = -34009 - case returnRefUnsupported = -34010 - case returnPersitentRefUnsupported = -34011 - case valueRefUnsupported = -34012 - case valuePersistentRefUnsupported = -34013 - case returnMissingPointer = -34014 - case matchLimitUnsupported = -34015 - case itemIllegalQuery = -34016 - case waitForCallback = -34017 - case missingEntitlement = -34018 - case upgradePending = -34019 - case mpSignatureInvalid = -25327 - case otrTooOld = -25328 - case otrIDTooNew = -25329 - case serviceNotAvailable = -67585 - case insufficientClientID = -67586 - case deviceReset = -67587 - case deviceFailed = -67588 - case appleAddAppACLSubject = -67589 - case applePublicKeyIncomplete = -67590 - case appleSignatureMismatch = -67591 - case appleInvalidKeyStartDate = -67592 - case appleInvalidKeyEndDate = -67593 - case conversionError = -67594 - case appleSSLv2Rollback = -67595 - case quotaExceeded = -67596 - case fileTooBig = -67597 - case invalidDatabaseBlob = -67598 - case invalidKeyBlob = -67599 - case incompatibleDatabaseBlob = -67600 - case incompatibleKeyBlob = -67601 - case hostNameMismatch = -67602 - case unknownCriticalExtensionFlag = -67603 - case noBasicConstraints = -67604 - case noBasicConstraintsCA = -67605 - case invalidAuthorityKeyID = -67606 - case invalidSubjectKeyID = -67607 - case invalidKeyUsageForPolicy = -67608 - case invalidExtendedKeyUsage = -67609 - case invalidIDLinkage = -67610 - case pathLengthConstraintExceeded = -67611 - case invalidRoot = -67612 - case crlExpired = -67613 - case crlNotValidYet = -67614 - case crlNotFound = -67615 - case crlServerDown = -67616 - case crlBadURI = -67617 - case unknownCertExtension = -67618 - case unknownCRLExtension = -67619 - case crlNotTrusted = -67620 - case crlPolicyFailed = -67621 - case idpFailure = -67622 - case smimeEmailAddressesNotFound = -67623 - case smimeBadExtendedKeyUsage = -67624 - case smimeBadKeyUsage = -67625 - case smimeKeyUsageNotCritical = -67626 - case smimeNoEmailAddress = -67627 - case smimeSubjAltNameNotCritical = -67628 - case sslBadExtendedKeyUsage = -67629 - case ocspBadResponse = -67630 - case ocspBadRequest = -67631 - case ocspUnavailable = -67632 - case ocspStatusUnrecognized = -67633 - case endOfData = -67634 - case incompleteCertRevocationCheck = -67635 - case networkFailure = -67636 - case ocspNotTrustedToAnchor = -67637 - case recordModified = -67638 - case ocspSignatureError = -67639 - case ocspNoSigner = -67640 - case ocspResponderMalformedReq = -67641 - case ocspResponderInternalError = -67642 - case ocspResponderTryLater = -67643 - case ocspResponderSignatureRequired = -67644 - case ocspResponderUnauthorized = -67645 - case ocspResponseNonceMismatch = -67646 - case codeSigningBadCertChainLength = -67647 - case codeSigningNoBasicConstraints = -67648 + case success = 0 + case unimplemented = -4 + case diskFull = -34 + case io = -36 + case opWr = -49 + case param = -50 + case wrPerm = -61 + case allocate = -108 + case userCanceled = -128 + case badReq = -909 + case internalComponent = -2070 + case notAvailable = -25291 + case readOnly = -25292 + case authFailed = -25293 + case noSuchKeychain = -25294 + case invalidKeychain = -25295 + case duplicateKeychain = -25296 + case duplicateCallback = -25297 + case invalidCallback = -25298 + case duplicateItem = -25299 + case itemNotFound = -25300 + case bufferTooSmall = -25301 + case dataTooLarge = -25302 + case noSuchAttr = -25303 + case invalidItemRef = -25304 + case invalidSearchRef = -25305 + case noSuchClass = -25306 + case noDefaultKeychain = -25307 + case interactionNotAllowed = -25308 + case readOnlyAttr = -25309 + case wrongSecVersion = -25310 + case keySizeNotAllowed = -25311 + case noStorageModule = -25312 + case noCertificateModule = -25313 + case noPolicyModule = -25314 + case interactionRequired = -25315 + case dataNotAvailable = -25316 + case dataNotModifiable = -25317 + case createChainFailed = -25318 + case invalidPrefsDomain = -25319 + case inDarkWake = -25320 + case aclNotSimple = -25240 + case policyNotFound = -25241 + case invalidTrustSetting = -25242 + case noAccessForItem = -25243 + case invalidOwnerEdit = -25244 + case trustNotAvailable = -25245 + case unsupportedFormat = -25256 + case unknownFormat = -25257 + case keyIsSensitive = -25258 + case multiplePrivKeys = -25259 + case passphraseRequired = -25260 + case invalidPasswordRef = -25261 + case invalidTrustSettings = -25262 + case noTrustSettings = -25263 + case pkcs12VerifyFailure = -25264 + case invalidCertificate = -26265 + case notSigner = -26267 + case policyDenied = -26270 + case invalidKey = -26274 + case decode = -26275 + case `internal` = -26276 + case unsupportedAlgorithm = -26268 + case unsupportedOperation = -26271 + case unsupportedPadding = -26273 + case itemInvalidKey = -34000 + case itemInvalidKeyType = -34001 + case itemInvalidValue = -34002 + case itemClassMissing = -34003 + case itemMatchUnsupported = -34004 + case useItemListUnsupported = -34005 + case useKeychainUnsupported = -34006 + case useKeychainListUnsupported = -34007 + case returnDataUnsupported = -34008 + case returnAttributesUnsupported = -34009 + case returnRefUnsupported = -34010 + case returnPersitentRefUnsupported = -34011 + case valueRefUnsupported = -34012 + case valuePersistentRefUnsupported = -34013 + case returnMissingPointer = -34014 + case matchLimitUnsupported = -34015 + case itemIllegalQuery = -34016 + case waitForCallback = -34017 + case missingEntitlement = -34018 + case upgradePending = -34019 + case mpSignatureInvalid = -25327 + case otrTooOld = -25328 + case otrIDTooNew = -25329 + case serviceNotAvailable = -67585 + case insufficientClientID = -67586 + case deviceReset = -67587 + case deviceFailed = -67588 + case appleAddAppACLSubject = -67589 + case applePublicKeyIncomplete = -67590 + case appleSignatureMismatch = -67591 + case appleInvalidKeyStartDate = -67592 + case appleInvalidKeyEndDate = -67593 + case conversionError = -67594 + case appleSSLv2Rollback = -67595 + case quotaExceeded = -67596 + case fileTooBig = -67597 + case invalidDatabaseBlob = -67598 + case invalidKeyBlob = -67599 + case incompatibleDatabaseBlob = -67600 + case incompatibleKeyBlob = -67601 + case hostNameMismatch = -67602 + case unknownCriticalExtensionFlag = -67603 + case noBasicConstraints = -67604 + case noBasicConstraintsCA = -67605 + case invalidAuthorityKeyID = -67606 + case invalidSubjectKeyID = -67607 + case invalidKeyUsageForPolicy = -67608 + case invalidExtendedKeyUsage = -67609 + case invalidIDLinkage = -67610 + case pathLengthConstraintExceeded = -67611 + case invalidRoot = -67612 + case crlExpired = -67613 + case crlNotValidYet = -67614 + case crlNotFound = -67615 + case crlServerDown = -67616 + case crlBadURI = -67617 + case unknownCertExtension = -67618 + case unknownCRLExtension = -67619 + case crlNotTrusted = -67620 + case crlPolicyFailed = -67621 + case idpFailure = -67622 + case smimeEmailAddressesNotFound = -67623 + case smimeBadExtendedKeyUsage = -67624 + case smimeBadKeyUsage = -67625 + case smimeKeyUsageNotCritical = -67626 + case smimeNoEmailAddress = -67627 + case smimeSubjAltNameNotCritical = -67628 + case sslBadExtendedKeyUsage = -67629 + case ocspBadResponse = -67630 + case ocspBadRequest = -67631 + case ocspUnavailable = -67632 + case ocspStatusUnrecognized = -67633 + case endOfData = -67634 + case incompleteCertRevocationCheck = -67635 + case networkFailure = -67636 + case ocspNotTrustedToAnchor = -67637 + case recordModified = -67638 + case ocspSignatureError = -67639 + case ocspNoSigner = -67640 + case ocspResponderMalformedReq = -67641 + case ocspResponderInternalError = -67642 + case ocspResponderTryLater = -67643 + case ocspResponderSignatureRequired = -67644 + case ocspResponderUnauthorized = -67645 + case ocspResponseNonceMismatch = -67646 + case codeSigningBadCertChainLength = -67647 + case codeSigningNoBasicConstraints = -67648 case codeSigningBadPathLengthConstraint = -67649 - case codeSigningNoExtendedKeyUsage = -67650 - case codeSigningDevelopment = -67651 - case resourceSignBadCertChainLength = -67652 - case resourceSignBadExtKeyUsage = -67653 - case trustSettingDeny = -67654 - case invalidSubjectName = -67655 - case unknownQualifiedCertStatement = -67656 - case mobileMeRequestQueued = -67657 - case mobileMeRequestRedirected = -67658 - case mobileMeServerError = -67659 - case mobileMeServerNotAvailable = -67660 - case mobileMeServerAlreadyExists = -67661 - case mobileMeServerServiceErr = -67662 - case mobileMeRequestAlreadyPending = -67663 - case mobileMeNoRequestPending = -67664 - case mobileMeCSRVerifyFailure = -67665 - case mobileMeFailedConsistencyCheck = -67666 - case notInitialized = -67667 - case invalidHandleUsage = -67668 - case pvcReferentNotFound = -67669 - case functionIntegrityFail = -67670 - case internalError = -67671 - case memoryError = -67672 - case invalidData = -67673 - case mdsError = -67674 - case invalidPointer = -67675 - case selfCheckFailed = -67676 - case functionFailed = -67677 - case moduleManifestVerifyFailed = -67678 - case invalidGUID = -67679 - case invalidHandle = -67680 - case invalidDBList = -67681 - case invalidPassthroughID = -67682 - case invalidNetworkAddress = -67683 - case crlAlreadySigned = -67684 - case invalidNumberOfFields = -67685 - case verificationFailure = -67686 - case unknownTag = -67687 - case invalidSignature = -67688 - case invalidName = -67689 - case invalidCertificateRef = -67690 - case invalidCertificateGroup = -67691 - case tagNotFound = -67692 - case invalidQuery = -67693 - case invalidValue = -67694 - case callbackFailed = -67695 - case aclDeleteFailed = -67696 - case aclReplaceFailed = -67697 - case aclAddFailed = -67698 - case aclChangeFailed = -67699 - case invalidAccessCredentials = -67700 - case invalidRecord = -67701 - case invalidACL = -67702 - case invalidSampleValue = -67703 - case incompatibleVersion = -67704 - case privilegeNotGranted = -67705 - case invalidScope = -67706 - case pvcAlreadyConfigured = -67707 - case invalidPVC = -67708 - case emmLoadFailed = -67709 - case emmUnloadFailed = -67710 - case addinLoadFailed = -67711 - case invalidKeyRef = -67712 - case invalidKeyHierarchy = -67713 - case addinUnloadFailed = -67714 - case libraryReferenceNotFound = -67715 - case invalidAddinFunctionTable = -67716 - case invalidServiceMask = -67717 - case moduleNotLoaded = -67718 - case invalidSubServiceID = -67719 - case attributeNotInContext = -67720 - case moduleManagerInitializeFailed = -67721 - case moduleManagerNotFound = -67722 - case eventNotificationCallbackNotFound = -67723 - case inputLengthError = -67724 - case outputLengthError = -67725 - case privilegeNotSupported = -67726 - case deviceError = -67727 - case attachHandleBusy = -67728 - case notLoggedIn = -67729 - case algorithmMismatch = -67730 - case keyUsageIncorrect = -67731 - case keyBlobTypeIncorrect = -67732 - case keyHeaderInconsistent = -67733 - case unsupportedKeyFormat = -67734 - case unsupportedKeySize = -67735 - case invalidKeyUsageMask = -67736 - case unsupportedKeyUsageMask = -67737 - case invalidKeyAttributeMask = -67738 - case unsupportedKeyAttributeMask = -67739 - case invalidKeyLabel = -67740 - case unsupportedKeyLabel = -67741 - case invalidKeyFormat = -67742 - case unsupportedVectorOfBuffers = -67743 - case invalidInputVector = -67744 - case invalidOutputVector = -67745 - case invalidContext = -67746 - case invalidAlgorithm = -67747 - case invalidAttributeKey = -67748 - case missingAttributeKey = -67749 - case invalidAttributeInitVector = -67750 - case missingAttributeInitVector = -67751 - case invalidAttributeSalt = -67752 - case missingAttributeSalt = -67753 - case invalidAttributePadding = -67754 - case missingAttributePadding = -67755 - case invalidAttributeRandom = -67756 - case missingAttributeRandom = -67757 - case invalidAttributeSeed = -67758 - case missingAttributeSeed = -67759 - case invalidAttributePassphrase = -67760 - case missingAttributePassphrase = -67761 - case invalidAttributeKeyLength = -67762 - case missingAttributeKeyLength = -67763 - case invalidAttributeBlockSize = -67764 - case missingAttributeBlockSize = -67765 - case invalidAttributeOutputSize = -67766 - case missingAttributeOutputSize = -67767 - case invalidAttributeRounds = -67768 - case missingAttributeRounds = -67769 - case invalidAlgorithmParms = -67770 - case missingAlgorithmParms = -67771 - case invalidAttributeLabel = -67772 - case missingAttributeLabel = -67773 - case invalidAttributeKeyType = -67774 - case missingAttributeKeyType = -67775 - case invalidAttributeMode = -67776 - case missingAttributeMode = -67777 - case invalidAttributeEffectiveBits = -67778 - case missingAttributeEffectiveBits = -67779 - case invalidAttributeStartDate = -67780 - case missingAttributeStartDate = -67781 - case invalidAttributeEndDate = -67782 - case missingAttributeEndDate = -67783 - case invalidAttributeVersion = -67784 - case missingAttributeVersion = -67785 - case invalidAttributePrime = -67786 - case missingAttributePrime = -67787 - case invalidAttributeBase = -67788 - case missingAttributeBase = -67789 - case invalidAttributeSubprime = -67790 - case missingAttributeSubprime = -67791 - case invalidAttributeIterationCount = -67792 - case missingAttributeIterationCount = -67793 - case invalidAttributeDLDBHandle = -67794 - case missingAttributeDLDBHandle = -67795 - case invalidAttributeAccessCredentials = -67796 - case missingAttributeAccessCredentials = -67797 - case invalidAttributePublicKeyFormat = -67798 - case missingAttributePublicKeyFormat = -67799 - case invalidAttributePrivateKeyFormat = -67800 - case missingAttributePrivateKeyFormat = -67801 + case codeSigningNoExtendedKeyUsage = -67650 + case codeSigningDevelopment = -67651 + case resourceSignBadCertChainLength = -67652 + case resourceSignBadExtKeyUsage = -67653 + case trustSettingDeny = -67654 + case invalidSubjectName = -67655 + case unknownQualifiedCertStatement = -67656 + case mobileMeRequestQueued = -67657 + case mobileMeRequestRedirected = -67658 + case mobileMeServerError = -67659 + case mobileMeServerNotAvailable = -67660 + case mobileMeServerAlreadyExists = -67661 + case mobileMeServerServiceErr = -67662 + case mobileMeRequestAlreadyPending = -67663 + case mobileMeNoRequestPending = -67664 + case mobileMeCSRVerifyFailure = -67665 + case mobileMeFailedConsistencyCheck = -67666 + case notInitialized = -67667 + case invalidHandleUsage = -67668 + case pvcReferentNotFound = -67669 + case functionIntegrityFail = -67670 + case internalError = -67671 + case memoryError = -67672 + case invalidData = -67673 + case mdsError = -67674 + case invalidPointer = -67675 + case selfCheckFailed = -67676 + case functionFailed = -67677 + case moduleManifestVerifyFailed = -67678 + case invalidGUID = -67679 + case invalidHandle = -67680 + case invalidDBList = -67681 + case invalidPassthroughID = -67682 + case invalidNetworkAddress = -67683 + case crlAlreadySigned = -67684 + case invalidNumberOfFields = -67685 + case verificationFailure = -67686 + case unknownTag = -67687 + case invalidSignature = -67688 + case invalidName = -67689 + case invalidCertificateRef = -67690 + case invalidCertificateGroup = -67691 + case tagNotFound = -67692 + case invalidQuery = -67693 + case invalidValue = -67694 + case callbackFailed = -67695 + case aclDeleteFailed = -67696 + case aclReplaceFailed = -67697 + case aclAddFailed = -67698 + case aclChangeFailed = -67699 + case invalidAccessCredentials = -67700 + case invalidRecord = -67701 + case invalidACL = -67702 + case invalidSampleValue = -67703 + case incompatibleVersion = -67704 + case privilegeNotGranted = -67705 + case invalidScope = -67706 + case pvcAlreadyConfigured = -67707 + case invalidPVC = -67708 + case emmLoadFailed = -67709 + case emmUnloadFailed = -67710 + case addinLoadFailed = -67711 + case invalidKeyRef = -67712 + case invalidKeyHierarchy = -67713 + case addinUnloadFailed = -67714 + case libraryReferenceNotFound = -67715 + case invalidAddinFunctionTable = -67716 + case invalidServiceMask = -67717 + case moduleNotLoaded = -67718 + case invalidSubServiceID = -67719 + case attributeNotInContext = -67720 + case moduleManagerInitializeFailed = -67721 + case moduleManagerNotFound = -67722 + case eventNotificationCallbackNotFound = -67723 + case inputLengthError = -67724 + case outputLengthError = -67725 + case privilegeNotSupported = -67726 + case deviceError = -67727 + case attachHandleBusy = -67728 + case notLoggedIn = -67729 + case algorithmMismatch = -67730 + case keyUsageIncorrect = -67731 + case keyBlobTypeIncorrect = -67732 + case keyHeaderInconsistent = -67733 + case unsupportedKeyFormat = -67734 + case unsupportedKeySize = -67735 + case invalidKeyUsageMask = -67736 + case unsupportedKeyUsageMask = -67737 + case invalidKeyAttributeMask = -67738 + case unsupportedKeyAttributeMask = -67739 + case invalidKeyLabel = -67740 + case unsupportedKeyLabel = -67741 + case invalidKeyFormat = -67742 + case unsupportedVectorOfBuffers = -67743 + case invalidInputVector = -67744 + case invalidOutputVector = -67745 + case invalidContext = -67746 + case invalidAlgorithm = -67747 + case invalidAttributeKey = -67748 + case missingAttributeKey = -67749 + case invalidAttributeInitVector = -67750 + case missingAttributeInitVector = -67751 + case invalidAttributeSalt = -67752 + case missingAttributeSalt = -67753 + case invalidAttributePadding = -67754 + case missingAttributePadding = -67755 + case invalidAttributeRandom = -67756 + case missingAttributeRandom = -67757 + case invalidAttributeSeed = -67758 + case missingAttributeSeed = -67759 + case invalidAttributePassphrase = -67760 + case missingAttributePassphrase = -67761 + case invalidAttributeKeyLength = -67762 + case missingAttributeKeyLength = -67763 + case invalidAttributeBlockSize = -67764 + case missingAttributeBlockSize = -67765 + case invalidAttributeOutputSize = -67766 + case missingAttributeOutputSize = -67767 + case invalidAttributeRounds = -67768 + case missingAttributeRounds = -67769 + case invalidAlgorithmParms = -67770 + case missingAlgorithmParms = -67771 + case invalidAttributeLabel = -67772 + case missingAttributeLabel = -67773 + case invalidAttributeKeyType = -67774 + case missingAttributeKeyType = -67775 + case invalidAttributeMode = -67776 + case missingAttributeMode = -67777 + case invalidAttributeEffectiveBits = -67778 + case missingAttributeEffectiveBits = -67779 + case invalidAttributeStartDate = -67780 + case missingAttributeStartDate = -67781 + case invalidAttributeEndDate = -67782 + case missingAttributeEndDate = -67783 + case invalidAttributeVersion = -67784 + case missingAttributeVersion = -67785 + case invalidAttributePrime = -67786 + case missingAttributePrime = -67787 + case invalidAttributeBase = -67788 + case missingAttributeBase = -67789 + case invalidAttributeSubprime = -67790 + case missingAttributeSubprime = -67791 + case invalidAttributeIterationCount = -67792 + case missingAttributeIterationCount = -67793 + case invalidAttributeDLDBHandle = -67794 + case missingAttributeDLDBHandle = -67795 + case invalidAttributeAccessCredentials = -67796 + case missingAttributeAccessCredentials = -67797 + case invalidAttributePublicKeyFormat = -67798 + case missingAttributePublicKeyFormat = -67799 + case invalidAttributePrivateKeyFormat = -67800 + case missingAttributePrivateKeyFormat = -67801 case invalidAttributeSymmetricKeyFormat = -67802 case missingAttributeSymmetricKeyFormat = -67803 - case invalidAttributeWrappedKeyFormat = -67804 - case missingAttributeWrappedKeyFormat = -67805 - case stagedOperationInProgress = -67806 - case stagedOperationNotStarted = -67807 - case verifyFailed = -67808 - case querySizeUnknown = -67809 - case blockSizeMismatch = -67810 - case publicKeyInconsistent = -67811 - case deviceVerifyFailed = -67812 - case invalidLoginName = -67813 - case alreadyLoggedIn = -67814 - case invalidDigestAlgorithm = -67815 - case invalidCRLGroup = -67816 - case certificateCannotOperate = -67817 - case certificateExpired = -67818 - case certificateNotValidYet = -67819 - case certificateRevoked = -67820 - case certificateSuspended = -67821 - case insufficientCredentials = -67822 - case invalidAction = -67823 - case invalidAuthority = -67824 - case verifyActionFailed = -67825 - case invalidCertAuthority = -67826 - case invaldCRLAuthority = -67827 - case invalidCRLEncoding = -67828 - case invalidCRLType = -67829 - case invalidCRL = -67830 - case invalidFormType = -67831 - case invalidID = -67832 - case invalidIdentifier = -67833 - case invalidIndex = -67834 - case invalidPolicyIdentifiers = -67835 - case invalidTimeString = -67836 - case invalidReason = -67837 - case invalidRequestInputs = -67838 - case invalidResponseVector = -67839 - case invalidStopOnPolicy = -67840 - case invalidTuple = -67841 - case multipleValuesUnsupported = -67842 - case notTrusted = -67843 - case noDefaultAuthority = -67844 - case rejectedForm = -67845 - case requestLost = -67846 - case requestRejected = -67847 - case unsupportedAddressType = -67848 - case unsupportedService = -67849 - case invalidTupleGroup = -67850 - case invalidBaseACLs = -67851 - case invalidTupleCredendtials = -67852 - case invalidEncoding = -67853 - case invalidValidityPeriod = -67854 - case invalidRequestor = -67855 - case requestDescriptor = -67856 - case invalidBundleInfo = -67857 - case invalidCRLIndex = -67858 - case noFieldValues = -67859 - case unsupportedFieldFormat = -67860 - case unsupportedIndexInfo = -67861 - case unsupportedLocality = -67862 - case unsupportedNumAttributes = -67863 - case unsupportedNumIndexes = -67864 - case unsupportedNumRecordTypes = -67865 - case fieldSpecifiedMultiple = -67866 - case incompatibleFieldFormat = -67867 - case invalidParsingModule = -67868 - case databaseLocked = -67869 - case datastoreIsOpen = -67870 - case missingValue = -67871 - case unsupportedQueryLimits = -67872 - case unsupportedNumSelectionPreds = -67873 - case unsupportedOperator = -67874 - case invalidDBLocation = -67875 - case invalidAccessRequest = -67876 - case invalidIndexInfo = -67877 - case invalidNewOwner = -67878 - case invalidModifyMode = -67879 - case missingRequiredExtension = -67880 - case extendedKeyUsageNotCritical = -67881 - case timestampMissing = -67882 - case timestampInvalid = -67883 - case timestampNotTrusted = -67884 - case timestampServiceNotAvailable = -67885 - case timestampBadAlg = -67886 - case timestampBadRequest = -67887 - case timestampBadDataFormat = -67888 - case timestampTimeNotAvailable = -67889 - case timestampUnacceptedPolicy = -67890 - case timestampUnacceptedExtension = -67891 - case timestampAddInfoNotAvailable = -67892 - case timestampSystemFailure = -67893 - case signingTimeMissing = -67894 - case timestampRejection = -67895 - case timestampWaiting = -67896 - case timestampRevocationWarning = -67897 - case timestampRevocationNotification = -67898 - case unexpectedError = -99999 + case invalidAttributeWrappedKeyFormat = -67804 + case missingAttributeWrappedKeyFormat = -67805 + case stagedOperationInProgress = -67806 + case stagedOperationNotStarted = -67807 + case verifyFailed = -67808 + case querySizeUnknown = -67809 + case blockSizeMismatch = -67810 + case publicKeyInconsistent = -67811 + case deviceVerifyFailed = -67812 + case invalidLoginName = -67813 + case alreadyLoggedIn = -67814 + case invalidDigestAlgorithm = -67815 + case invalidCRLGroup = -67816 + case certificateCannotOperate = -67817 + case certificateExpired = -67818 + case certificateNotValidYet = -67819 + case certificateRevoked = -67820 + case certificateSuspended = -67821 + case insufficientCredentials = -67822 + case invalidAction = -67823 + case invalidAuthority = -67824 + case verifyActionFailed = -67825 + case invalidCertAuthority = -67826 + case invaldCRLAuthority = -67827 + case invalidCRLEncoding = -67828 + case invalidCRLType = -67829 + case invalidCRL = -67830 + case invalidFormType = -67831 + case invalidID = -67832 + case invalidIdentifier = -67833 + case invalidIndex = -67834 + case invalidPolicyIdentifiers = -67835 + case invalidTimeString = -67836 + case invalidReason = -67837 + case invalidRequestInputs = -67838 + case invalidResponseVector = -67839 + case invalidStopOnPolicy = -67840 + case invalidTuple = -67841 + case multipleValuesUnsupported = -67842 + case notTrusted = -67843 + case noDefaultAuthority = -67844 + case rejectedForm = -67845 + case requestLost = -67846 + case requestRejected = -67847 + case unsupportedAddressType = -67848 + case unsupportedService = -67849 + case invalidTupleGroup = -67850 + case invalidBaseACLs = -67851 + case invalidTupleCredendtials = -67852 + case invalidEncoding = -67853 + case invalidValidityPeriod = -67854 + case invalidRequestor = -67855 + case requestDescriptor = -67856 + case invalidBundleInfo = -67857 + case invalidCRLIndex = -67858 + case noFieldValues = -67859 + case unsupportedFieldFormat = -67860 + case unsupportedIndexInfo = -67861 + case unsupportedLocality = -67862 + case unsupportedNumAttributes = -67863 + case unsupportedNumIndexes = -67864 + case unsupportedNumRecordTypes = -67865 + case fieldSpecifiedMultiple = -67866 + case incompatibleFieldFormat = -67867 + case invalidParsingModule = -67868 + case databaseLocked = -67869 + case datastoreIsOpen = -67870 + case missingValue = -67871 + case unsupportedQueryLimits = -67872 + case unsupportedNumSelectionPreds = -67873 + case unsupportedOperator = -67874 + case invalidDBLocation = -67875 + case invalidAccessRequest = -67876 + case invalidIndexInfo = -67877 + case invalidNewOwner = -67878 + case invalidModifyMode = -67879 + case missingRequiredExtension = -67880 + case extendedKeyUsageNotCritical = -67881 + case timestampMissing = -67882 + case timestampInvalid = -67883 + case timestampNotTrusted = -67884 + case timestampServiceNotAvailable = -67885 + case timestampBadAlg = -67886 + case timestampBadRequest = -67887 + case timestampBadDataFormat = -67888 + case timestampTimeNotAvailable = -67889 + case timestampUnacceptedPolicy = -67890 + case timestampUnacceptedExtension = -67891 + case timestampAddInfoNotAvailable = -67892 + case timestampSystemFailure = -67893 + case signingTimeMissing = -67894 + case timestampRejection = -67895 + case timestampWaiting = -67896 + case timestampRevocationWarning = -67897 + case timestampRevocationNotification = -67898 + case unexpectedError = -99999 } extension Status: RawRepresentable, CustomStringConvertible { @@ -2908,7 +2936,7 @@ extension Status: CustomNSError { return Int(rawValue) } - public var errorUserInfo: [String : Any] { + public var errorUserInfo: [String: Any] { return [NSLocalizedDescriptionKey: description] } } diff --git a/SCP/MasterViewController.swift b/SCP/MasterViewController.swift index 3b6722b..a9d4f2f 100644 --- a/SCP/MasterViewController.swift +++ b/SCP/MasterViewController.swift @@ -10,7 +10,6 @@ import UIKit class MasterViewController: UITableViewController { - var detailViewController: DetailViewController? = nil var keys = [String]() var keychain:Keychain? = nil; @@ -21,17 +20,12 @@ class MasterViewController: UITableViewController { let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:))) navigationItem.rightBarButtonItem = addButton - if let split = splitViewController { - let controllers = split.viewControllers - detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController - } keychain = Keychain() keys = (keychain?.allKeys())!; } override func viewWillAppear(_ animated: Bool) { - clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed super.viewWillAppear(animated) if((keychain) != nil) { keys = (keychain?.allKeys())!; @@ -59,17 +53,23 @@ class MasterViewController: UITableViewController { let Key = keys[indexPath.row] let Value = try keychain?.get(Key); controller.detailItem = Value! + controller.detailItemUUID = Key } catch _ { controller.detailItem = "Key Doesn't Exist" } - controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem controller.navigationItem.leftItemsSupplementBackButton = true + + self.tableView.deselectRow(at: indexPath, animated: false) } } } // MARK: - Table View + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + self.performSegue(withIdentifier: "showDetail", sender: nil) + } + override func numberOfSections(in tableView: UITableView) -> Int { return 1 } diff --git a/SCP/SSHServerTableViewController.swift b/SCP/SSHServerTableViewController.swift index 0e4b64a..964eb85 100644 --- a/SCP/SSHServerTableViewController.swift +++ b/SCP/SSHServerTableViewController.swift @@ -24,6 +24,7 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab var sideListener: ((_ path:String) -> ())? var executionListener: (()->())? var sshQueue:DispatchQueue? + var serverUUID:String! override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) @@ -39,10 +40,17 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab } self.title = SSHServer?.name - self.tableView?.dataSource = self; - self.tableView?.delegate = self; - self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: isLeft ? "LeftTableCell" : "RightTableCell") + DispatchQueue.main.async { + self.tableView?.dataSource = self; + self.tableView?.delegate = self; + self.tableView?.register(UITableViewCell.self, forCellReuseIdentifier: self.isLeft ? "LeftTableCell" : "RightTableCell") + } + if(isLeft) { + pwd = (UserDefaults.standard.object(forKey: self.serverUUID + "_last_path_left") as? String) ?? "" + } else { + pwd = (UserDefaults.standard.object(forKey: self.serverUUID + "_last_path_right") as? String) ?? "" + } SSHSession = NMSSHSession.connect(toHost: SSHServer?.host, port: (SSHServer?.port)!, withUsername: SSHServer?.user) if (SSHSession?.isConnected)! { @@ -77,7 +85,9 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab let dirs = try SSHSession?.channel.execute("cd \"" + pwd + "\" && ls -d1 */") parseListing(all: list!, dirs: dirs!); - tableView?.reloadData() + DispatchQueue.main.async { + self.tableView?.reloadData() + } } catch let error { print("error: \(error)") } @@ -110,7 +120,11 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab do { pwd = (try SSHSession?.channel.execute("cd \"" + pwd + "\" && cd \"" + path + "\" && pwd"))! pwd = pwd.trimmingCharacters(in: .whitespacesAndNewlines) - + if(isLeft) { + UserDefaults.standard.set(pwd, forKey: self.serverUUID + "_last_path_left") + } else { + UserDefaults.standard.set(pwd, forKey: self.serverUUID + "_last_path_right") + } sideListener!(pwd) objects = [] @@ -140,11 +154,12 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab cell.textLabel?.text = item["name"] if(item["type"] == "folder") { cell.imageView?.image = UIImage.init(icon: .fontAwesome(.folder), size: CGSize(width: 35, height: 35)) - let holdForAction = UILongPressGestureRecognizer(target: self, action: #selector(SSHServerTableViewController.longPressFolder)); - cell.addGestureRecognizer(holdForAction) } else if(item["type"] == "file") { cell.imageView?.image = UIImage.init(icon: .fontAwesome(.file), size: CGSize(width: 35, height: 35)) } + let holdForAction = UILongPressGestureRecognizer(target: self, action: #selector(SSHServerTableViewController.longPressFolder)); + cell.addGestureRecognizer(holdForAction) + return cell } @@ -156,6 +171,8 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab } else if(item["type"] == "file") { handleAction(item, indexPath: indexPath) } + + tableView.deselectRow(at: indexPath, animated: true) } @objc public func longPressFolder(sender: UILongPressGestureRecognizer) { @@ -228,6 +245,10 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab self.handleView(path: self.pwd + "/" + item["name"]!) })) + alert.addAction(UIAlertAction(title: "Stats", style: .default, handler: { (action) in + self.handleStats(path: self.pwd + "/" + item["name"]!) + })) + alert.addAction(UIAlertAction(title: "Move", style: .destructive, handler: { (action) in self.handleMove(from: self.pwd + "/" + item["name"]!, to: self.sidePWD) })) @@ -288,7 +309,21 @@ class SSHServerTableViewController: UIViewController, UITableViewDelegate, UITab let viewAlert = UIAlertController(title: "Viewing " + path, message: cat, preferredStyle: .alert) viewAlert.addAction(UIAlertAction(title: "Done", style: .default)) - + + self.presenter!(viewAlert, true, nil) + } catch let error { + print("error: \(error)") + } + } + + + private func handleStats(path: String) { + do { + let cat = try SSHSession?.channel.execute("ls -alh \"" + path + "\"") + + let viewAlert = UIAlertController(title: "Stats " + path, message: cat, preferredStyle: .alert) + viewAlert.addAction(UIAlertAction(title: "Done", style: .default)) + self.presenter!(viewAlert, true, nil) } catch let error { print("error: \(error)")