// // SharedWebCredentialsManager.swift // Keychain // // Created by Mohammad Alatrash on 6/14/18. // import Foundation enum SharedWebCredentialsManagerError: Error { case noCredentialsFound case generatePasswordFailed case saveFailed(String) case deleteFailed(String) } class SharedWebCredentialsManager { static let shared = SharedWebCredentialsManager() let domain: String = "www.domain.com" func request(_ completion: (String?, String?, SharedWebCredentialsManagerError?) -> Void) { SecRequestSharedWebCredential(domain as CFString, nil) { (credentials, error) in guard let credentials = credentials, CFArrayGetCount(credentials) > 0 else { completion(nil, nil, SharedWebCredentialsManagerError.noCredentialsFound) return } let credential = CFArrayGetValueAtIndex(credentials, 0) let credentialDict = unsafeBitCast(credential, to: CFDictionary.self) let unsafeAccount = CFDictionaryGetValue(credentialDict, Unmanaged.passUnretained(kSecAttrAccount).toOpaque()) let account = unsafeBitCast(unsafeAccount, to: CFString.self) as String let unsafePassword = CFDictionaryGetValue(credentialDict, Unmanaged.passUnretained(kSecSharedPassword).toOpaque()) let password = unsafeBitCast(unsafePassword, to: CFString.self) as String completion(account, password, nil) } } func save(account: String, password: String, completion: ((Bool, SharedWebCredentialsManagerError?) -> Void)? = nil) { SecAddSharedWebCredential(domain as CFString, account as CFString, password as CFString?) { error in guard let error = error else { completion?(true, nil) return } let errorDescription = CFErrorCopyDescription(error) as String let saveFailedError = SharedWebCredentialsManagerError.saveFailed(errorDescription) completion?(false, saveFailedError) } } func delete(account: String, completion: ((Bool, SharedWebCredentialsManagerError?) -> Void)? = nil) -> Promise { SecAddSharedWebCredential(domain as CFString, account as CFString, nil) { error in guard let error = error else { completion?(true, nil) return } let errorDescription = CFErrorCopyDescription(error) as String let deleteFailedError = SharedWebCredentialsManagerError.saveFailed(errorDescription) completion?(true, deleteFailedError) } } func generatePassword(_ completion: ((String?, SharedWebCredentialsManagerError?) -> Void)? = nil) { guard let password = SecCreateSharedWebCredentialPassword() as String? else { completion?(nil, SharedWebCredentialsManagerError.generatePasswordFailed) return } completion?(password, nil) } }