From d8866d55f3454e178ddf604d03b052b5d53bd4f6 Mon Sep 17 00:00:00 2001 From: luka dodelia Date: Wed, 29 Aug 2018 14:47:23 +0400 Subject: [PATCH] 1.1v --- .gitignore | 1 + .../xcschemes/xcschememanagement.plist | 4 +- SCP.xcodeproj/project.pbxproj | 17 + .../UserInterfaceState.xcuserstate | Bin 101692 -> 102958 bytes .../xcschemes/xcschememanagement.plist | 5 + SCP/AddServerViewController.swift | 132 +-- SCP/AppDelegate.swift | 19 +- SCP/Base.lproj/Main.storyboard | 24 +- SCP/DetailViewController.swift | 105 +- SCP/Info.plist | 4 +- SCP/Keychain.swift | 966 +++++++++--------- SCP/MasterViewController.swift | 14 +- SCP/SSHServerTableViewController.swift | 51 +- 13 files changed, 712 insertions(+), 630 deletions(-) create mode 100644 SCP.xcodeproj/project.xcworkspace/xcuserdata/ld.xcuserdatad/xcschemes/xcschememanagement.plist 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 83c9f3fcd925d8b71240c9c8c4c6f959e7570b61..94e21c1be0e1fc676340bff0a5dac174a84ba473 100644 GIT binary patch literal 102958 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 literal 101692 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 Z!Q(`#f7E!OLiLZnWAmSH|0~5!{eP~P4v7E& 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)")