// KeychainHelper.swift // Secure storage helper for API keys and sensitive data import Foundation import Security /// Manages secure storage of sensitive data using the macOS Keychain class KeychainHelper { static let shared = KeychainHelper() private let serviceName = "owen.notetaker" private init() {} /// Saves a string value to the keychain /// - Parameters: /// - value: The string value to save /// - key: The key to save the value under /// - Returns: True if the save was successful, false otherwise func save(_ value: String, forKey key: String) -> Bool { guard let data = value.data(using: .utf8) else { return false } let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecValueData as String: data, kSecAttrService as String: serviceName ] // Delete any existing item SecItemDelete(query as CFDictionary) // Add the new item let status = SecItemAdd(query as CFDictionary, nil) return status == errSecSuccess } /// Retrieves a string value from the keychain /// - Parameter key: The key to retrieve the value for /// - Returns: The string value if found, nil otherwise func get(forKey key: String) -> String? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecAttrService as String: serviceName, kSecMatchLimit as String: kSecMatchLimitOne, kSecReturnData as String: true ] var item: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &item) guard status == errSecSuccess, let data = item as? Data else { return nil } return String(data: data, encoding: .utf8) } /// Deletes a value from the keychain /// - Parameter key: The key to delete /// - Returns: True if the deletion was successful, false otherwise func delete(forKey key: String) -> Bool { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecAttrService as String: serviceName ] let status = SecItemDelete(query as CFDictionary) return status == errSecSuccess } }