import Foundation import PolicyCore import Security enum KeychainStore { private static var query: [String: Any] { [kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: Bundle.main.bundleIdentifier ?? "APC", kSecAttrAccount as String: "paired-device"] } static func load() throws -> Credentials? { var request = query request[kSecReturnData as String] = true request[kSecMatchLimit as String] = kSecMatchLimitOne var item: CFTypeRef? let status = SecItemCopyMatching(request as CFDictionary, &item) if status == errSecItemNotFound { return nil } guard status == errSecSuccess, let data = item as? Data else { throw LocalError.message("Cannot read pairing credentials: \(status)") } return try WireCoding.decoder().decode(Credentials.self, from: data) } static func save(_ credentials: Credentials) throws { let data = try WireCoding.encoder().encode(credentials) let update = [kSecValueData as String: data] let result = SecItemUpdate(query as CFDictionary, update as CFDictionary) if result == errSecItemNotFound { var insert = query insert[kSecValueData as String] = data insert[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly let status = SecItemAdd(insert as CFDictionary, nil) guard status == errSecSuccess else { throw LocalError.message("Cannot save pairing: \(status)") } } else if result != errSecSuccess { throw LocalError.message("Cannot update pairing: \(result)") } } }