parent
e1f004d80a
commit
92b35c7c0f
@ -0,0 +1,66 @@ |
|||||||
|
// |
||||||
|
// KeychainStore.swift |
||||||
|
// LeCountdown |
||||||
|
// |
||||||
|
// Created by Laurent Morvillier on 20/12/2023. |
||||||
|
// |
||||||
|
|
||||||
|
import Foundation |
||||||
|
|
||||||
|
enum KeychainError: Error { |
||||||
|
case noPassword |
||||||
|
case unexpectedPasswordData |
||||||
|
case unhandledError(status: OSStatus) |
||||||
|
} |
||||||
|
|
||||||
|
class KeychainStore { |
||||||
|
|
||||||
|
let serverId: String |
||||||
|
|
||||||
|
init(serverId: String) { |
||||||
|
self.serverId = serverId |
||||||
|
} |
||||||
|
|
||||||
|
func add(username: String, token: String) throws { |
||||||
|
let tokenData = token.data(using: .utf8)! |
||||||
|
let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, |
||||||
|
kSecAttrAccount as String: username, |
||||||
|
kSecAttrServer as String: self.serverId, |
||||||
|
kSecValueData as String: tokenData] |
||||||
|
|
||||||
|
let status = SecItemAdd(query as CFDictionary, nil) |
||||||
|
guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) } |
||||||
|
} |
||||||
|
|
||||||
|
func getToken() throws -> String { |
||||||
|
|
||||||
|
let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, |
||||||
|
kSecAttrServer as String: self.serverId, |
||||||
|
kSecMatchLimit as String: kSecMatchLimitOne, |
||||||
|
kSecReturnAttributes as String: true, |
||||||
|
kSecReturnData as String: true] |
||||||
|
|
||||||
|
var item: CFTypeRef? |
||||||
|
let status = SecItemCopyMatching(query as CFDictionary, &item) |
||||||
|
guard status != errSecItemNotFound else { throw KeychainError.noPassword } |
||||||
|
guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) } |
||||||
|
|
||||||
|
guard let existingItem = item as? [String : Any], |
||||||
|
let tokenData = existingItem[kSecValueData as String] as? Data, |
||||||
|
let token = String(data: tokenData, encoding: .utf8) |
||||||
|
else { |
||||||
|
throw KeychainError.unexpectedPasswordData |
||||||
|
} |
||||||
|
return token |
||||||
|
} |
||||||
|
|
||||||
|
func deleteToken() throws { |
||||||
|
|
||||||
|
let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, |
||||||
|
kSecAttrServer as String: self.serverId] |
||||||
|
|
||||||
|
let status = SecItemDelete(query as CFDictionary) |
||||||
|
guard status == errSecSuccess || status == errSecItemNotFound else { throw KeychainError.unhandledError(status: status) } |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue