import Foundation import Security /// Minimal Keychain wrapper for the API token and instance URL. enum KeychainHelper { private static let service = "com.bueso.giteapr" static func set(_ value: String, key: String) { guard let data = value.data(using: .utf8) else { return } let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: key, ] // Delete any existing item first (upsert semantics). SecItemDelete(query as CFDictionary) var attrs = query attrs[kSecValueData as String] = data attrs[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock SecItemAdd(attrs as CFDictionary, nil) } static func get(_ key: String) -> String? { 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, let data = result as? Data, let string = String(data: data, encoding: .utf8) else { return nil } return string } 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) } }