// // KeychainStore.swift // punchnet // // Created by 安礼成 on 2026/1/19. // import Foundation import Security enum KeychainError: Error { case unexpectedStatus(OSStatus) } final class KeychainStore { public static var shared: KeychainStore = .init(service: Bundle.main.bundleIdentifier!) private let service: String private init(service: String) { self.service = service } func save(_ data: Data, account: String) throws { let query: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecValueData: data ] // 先删再加,避免重复 SecItemDelete(query as CFDictionary) let status = SecItemAdd(query as CFDictionary, nil) guard status == errSecSuccess else { throw KeychainError.unexpectedStatus(status) } } func load(account: String) throws -> Data? { let query: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecReturnData: true, kSecMatchLimit: kSecMatchLimitOne ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) if status == errSecItemNotFound { return nil } guard status == errSecSuccess else { throw KeychainError.unexpectedStatus(status) } return result as? Data } func delete(account: String) throws { let query: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account ] let status = SecItemDelete(query as CFDictionary) guard status == errSecSuccess || status == errSecItemNotFound else { throw KeychainError.unexpectedStatus(status) } } }