05/02 Phase C 2
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
// Thin wrapper around iOS Security framework for storing sensitive data
|
||||
// (tokens) in the device Keychain.
|
||||
//
|
||||
// The Keychain persists across app reinstalls (on the same device) and
|
||||
// is encrypted by the OS. Never store tokens in UserDefaults.
|
||||
// All methods are marked nonisolated so they can be called from any
|
||||
// actor context (including APIClient which is an actor) without
|
||||
// Swift 6 actor-isolation warnings.
|
||||
// Security framework calls are internally thread-safe.
|
||||
|
||||
import Foundation
|
||||
import Security
|
||||
@@ -15,10 +17,9 @@ enum KeychainHelper {
|
||||
// ── Write ─────────────────────────────────────────────────────────────
|
||||
|
||||
@discardableResult
|
||||
static func set(_ value: String, forKey key: String) -> Bool {
|
||||
nonisolated static func set(_ value: String, forKey key: String) -> Bool {
|
||||
guard let data = value.data(using: .utf8) else { return false }
|
||||
|
||||
// Delete any existing entry first to avoid duplicate-item errors
|
||||
let deleteQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrAccount as String: key,
|
||||
@@ -26,10 +27,10 @@ enum KeychainHelper {
|
||||
SecItemDelete(deleteQuery as CFDictionary)
|
||||
|
||||
let addQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrAccount as String: key,
|
||||
kSecValueData as String: data,
|
||||
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrAccount as String: key,
|
||||
kSecValueData as String: data,
|
||||
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
|
||||
]
|
||||
let status = SecItemAdd(addQuery as CFDictionary, nil)
|
||||
return status == errSecSuccess
|
||||
@@ -37,7 +38,7 @@ enum KeychainHelper {
|
||||
|
||||
// ── Read ──────────────────────────────────────────────────────────────
|
||||
|
||||
static func get(_ key: String) -> String? {
|
||||
nonisolated static func get(_ key: String) -> String? {
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrAccount as String: key,
|
||||
@@ -56,7 +57,7 @@ enum KeychainHelper {
|
||||
// ── Delete ────────────────────────────────────────────────────────────
|
||||
|
||||
@discardableResult
|
||||
static func delete(_ key: String) -> Bool {
|
||||
nonisolated static func delete(_ key: String) -> Bool {
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrAccount as String: key,
|
||||
@@ -67,7 +68,7 @@ enum KeychainHelper {
|
||||
|
||||
// ── Delete All JQC Keys ───────────────────────────────────────────────
|
||||
|
||||
static func clearAll() {
|
||||
nonisolated static func clearAll() {
|
||||
let keys = [
|
||||
Constants.Keychain.accessToken,
|
||||
Constants.Keychain.refreshToken,
|
||||
|
||||
Reference in New Issue
Block a user