36 lines
1.6 KiB
Swift
36 lines
1.6 KiB
Swift
import Foundation
|
|
import PolicyCore
|
|
import Security
|
|
|
|
enum KeychainStore {
|
|
private static var query: [String: Any] {
|
|
[kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: Bundle.main.bundleIdentifier ?? "APC",
|
|
kSecAttrAccount as String: "paired-device"]
|
|
}
|
|
static func load() throws -> Credentials? {
|
|
var request = query
|
|
request[kSecReturnData as String] = true
|
|
request[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
var item: CFTypeRef?
|
|
let status = SecItemCopyMatching(request as CFDictionary, &item)
|
|
if status == errSecItemNotFound { return nil }
|
|
guard status == errSecSuccess, let data = item as? Data else {
|
|
throw LocalError.message("Cannot read pairing credentials: \(status)")
|
|
}
|
|
return try WireCoding.decoder().decode(Credentials.self, from: data)
|
|
}
|
|
static func save(_ credentials: Credentials) throws {
|
|
let data = try WireCoding.encoder().encode(credentials)
|
|
let update = [kSecValueData as String: data]
|
|
let result = SecItemUpdate(query as CFDictionary, update as CFDictionary)
|
|
if result == errSecItemNotFound {
|
|
var insert = query
|
|
insert[kSecValueData as String] = data
|
|
insert[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
let status = SecItemAdd(insert as CFDictionary, nil)
|
|
guard status == errSecSuccess else { throw LocalError.message("Cannot save pairing: \(status)") }
|
|
} else if result != errSecSuccess { throw LocalError.message("Cannot update pairing: \(result)") }
|
|
}
|
|
}
|