summaryrefslogtreecommitdiff
path: root/Hutch/Extensions
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-01 11:36:01 -0500
committerChristian Cleberg <[email protected]>2026-04-01 11:37:35 -0500
commit7b59ee6098c4649a51cafe4b58e3a675567e2c08 (patch)
tree3ec7aa3c843c13d24a164d89f1d724ac48d2210a /Hutch/Extensions
parent3f03c433a7435e283244e94f09bd513bd45f3202 (diff)
downloadhutch-7b59ee6098c4649a51cafe4b58e3a675567e2c08.tar.gz
hutch-7b59ee6098c4649a51cafe4b58e3a675567e2c08.tar.bz2
hutch-7b59ee6098c4649a51cafe4b58e3a675567e2c08.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.swift40
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 {