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