114 lines
3.9 KiB
Swift
114 lines
3.9 KiB
Swift
import Foundation
|
||
import Security
|
||
|
||
|
||
//let username = "user1"
|
||
|
||
// Сохраняем токены
|
||
//KeychainService.shared.save("access_token_value", forKey: "access_token", service: username)
|
||
//KeychainService.shared.save("refresh_token_value", forKey: "refresh_token", service: username)
|
||
|
||
// Получаем токены
|
||
//let accessToken = KeychainService.shared.get(forKey: "access_token", service: username)
|
||
//let refreshToken = KeychainService.shared.get(forKey: "refresh_token", service: username)
|
||
|
||
// получение всех пользователей
|
||
//let users = KeychainService.shared.getAllServices()
|
||
//print("Все пользователи: \(users)")
|
||
|
||
// Удаление всех пользователей
|
||
//KeychainService.shared.deleteAll()
|
||
|
||
// удаление по одному
|
||
//KeychainService.shared.delete(forKey: "access_token", service: username)
|
||
//KeychainService.shared.delete(forKey: "refresh_token", service: username)
|
||
|
||
|
||
class KeychainService {
|
||
|
||
static let shared = KeychainService()
|
||
|
||
private init() {}
|
||
|
||
func save(_ value: String, forKey key: String, service: String) {
|
||
guard let data = value.data(using: .utf8) else { return }
|
||
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword,
|
||
kSecAttrService as String: service, // ключ группировки
|
||
kSecAttrAccount as String: key,
|
||
kSecValueData as String: data
|
||
]
|
||
|
||
SecItemDelete(query as CFDictionary)
|
||
let status = SecItemAdd(query as CFDictionary, nil)
|
||
if status != errSecSuccess {
|
||
print("Error saving to Keychain: \(status)")
|
||
}
|
||
}
|
||
|
||
func get(forKey key: String, service: String) -> String? {
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword,
|
||
kSecAttrService as String: service,
|
||
kSecAttrAccount as String: key,
|
||
kSecReturnData as String: true,
|
||
kSecMatchLimit as String: kSecMatchLimitOne
|
||
]
|
||
|
||
var dataTypeRef: AnyObject?
|
||
let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
|
||
if status == errSecSuccess,
|
||
let data = dataTypeRef as? Data,
|
||
let value = String(data: data, encoding: .utf8) {
|
||
return value
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func getAllServices() -> [String] {
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword,
|
||
kSecReturnAttributes as String: true,
|
||
kSecMatchLimit as String: kSecMatchLimitAll
|
||
]
|
||
|
||
var result: AnyObject?
|
||
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
||
|
||
guard status == errSecSuccess, let items = result as? [[String: Any]] else {
|
||
return []
|
||
}
|
||
|
||
// Собираем все уникальные service (username)
|
||
var services = Set<String>()
|
||
for item in items {
|
||
if let service = item[kSecAttrService as String] as? String {
|
||
services.insert(service)
|
||
}
|
||
}
|
||
|
||
return Array(services)
|
||
}
|
||
|
||
func delete(forKey key: String, service: String) {
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword,
|
||
kSecAttrService as String: service,
|
||
kSecAttrAccount as String: key
|
||
]
|
||
SecItemDelete(query as CFDictionary)
|
||
}
|
||
|
||
/// Удалить все записи Keychain, сохранённые этим приложением
|
||
func deleteAll() {
|
||
let query: [String: Any] = [
|
||
kSecClass as String: kSecClassGenericPassword
|
||
]
|
||
let status = SecItemDelete(query as CFDictionary)
|
||
if status != errSecSuccess && status != errSecItemNotFound {
|
||
print("Error deleting all Keychain items: \(status)")
|
||
}
|
||
}
|
||
}
|