// // KeychainHelper.swift // iris // // Secure token storage using iOS Keychain. // import Foundation import Security enum KeychainHelper { private static let service = "sh.nym.iris.spotify" static func save(key: String, data: Data) throws { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key ] SecItemDelete(query as CFDictionary) let attributes: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key, kSecValueData as String: data, kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock ] let status = SecItemAdd(attributes as CFDictionary, nil) guard status == errSecSuccess else { throw KeychainError.saveFailed(status) } } static func load(key: String) -> Data? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key, kSecReturnData as String: true, kSecMatchLimit as String: kSecMatchLimitOne ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) guard status == errSecSuccess else { return nil } return result as? Data } static func delete(key: String) { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key ] SecItemDelete(query as CFDictionary) } enum KeychainError: Error { case saveFailed(OSStatus) } }