hololake-system-architecture/product-source/hololake-native-desktop/mobile/ios/Sources/HoloLakeKeychain.swift

59 lines
2.3 KiB
Swift

import Foundation
import Security
enum HoloLakeKeychain {
private static let service = "com.guanghulab.hololake.mobile-sync"
private static let account = "HLP-IOS-CLIENT-001"
static func load() throws -> StoredSession? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecItemNotFound { return nil }
guard status == errSecSuccess, let data = result as? Data else {
throw HoloLakeMobileError.keychain(status)
}
return try JSONDecoder().decode(StoredSession.self, from: data)
}
static func save(_ session: StoredSession) throws {
let data = try JSONEncoder().encode(session)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
let attributes: [String: Any] = [
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
let update = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if update == errSecItemNotFound {
var insertion = query
insertion.merge(attributes) { _, new in new }
let status = SecItemAdd(insertion as CFDictionary, nil)
guard status == errSecSuccess else { throw HoloLakeMobileError.keychain(status) }
} else if update != errSecSuccess {
throw HoloLakeMobileError.keychain(update)
}
}
static func remove() throws {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
let status = SecItemDelete(query as CFDictionary)
guard status == errSecSuccess || status == errSecItemNotFound else {
throw HoloLakeMobileError.keychain(status)
}
}
}