diff options
| author | Christian Cleberg <[email protected]> | 2026-04-01 11:36:01 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-01 11:37:35 -0500 |
| commit | 7b59ee6098c4649a51cafe4b58e3a675567e2c08 (patch) | |
| tree | 3ec7aa3c843c13d24a164d89f1d724ac48d2210a /Hutch/Extensions | |
| parent | 3f03c433a7435e283244e94f09bd513bd45f3202 (diff) | |
| download | hutch-2.6.0.tar.gz hutch-2.6.0.tar.bz2 hutch-2.6.0.zip | |
feat: add multi-account supportv2.6.0
Implements: https://todo.sr.ht/~ccleberg/Hutch/11
Diffstat (limited to 'Hutch/Extensions')
| -rw-r--r-- | Hutch/Extensions/KeychainHelper.swift | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/Hutch/Extensions/KeychainHelper.swift b/Hutch/Extensions/KeychainHelper.swift index 01f8e5a..d53c80e 100644 --- a/Hutch/Extensions/KeychainHelper.swift +++ b/Hutch/Extensions/KeychainHelper.swift @@ -5,6 +5,7 @@ enum KeychainHelper: Sendable { private static let service = "net.cleberg.Hutch" private static let tokenAccount = "srht-access-token" + private static let accountsAccount = "srht-accounts" // MARK: - Save @@ -57,6 +58,45 @@ enum KeychainHelper: Sendable { return token } + // MARK: - Multi-account list + + static func saveAccounts(_ accounts: [AccountEntry]) throws { + let data = try JSONEncoder().encode(accounts) + + let deleteQuery: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrService as String: service, + kSecAttrAccount as String: accountsAccount + ] + SecItemDelete(deleteQuery as CFDictionary) + + let addQuery: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrService as String: service, + kSecAttrAccount as String: accountsAccount, + kSecValueData as String: data, + kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly + ] + let status = SecItemAdd(addQuery as CFDictionary, nil) + guard status == errSecSuccess else { + throw KeychainError.saveFailed(status) + } + } + + static func loadAccounts() -> [AccountEntry] { + let query: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrService as String: service, + kSecAttrAccount as String: accountsAccount, + kSecReturnData as String: true, + kSecMatchLimit as String: kSecMatchLimitOne + ] + var result: AnyObject? + guard SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess, + let data = result as? Data else { return [] } + return (try? JSONDecoder().decode([AccountEntry].self, from: data)) ?? [] + } + // MARK: - Delete static func deleteToken() throws { |
