42 lines
2.0 KiB
Swift
42 lines
2.0 KiB
Swift
|
|
import Foundation
|
||
|
|
import Security
|
||
|
|
|
||
|
|
enum KeychainStore {
|
||
|
|
private static var query: [String: Any] {
|
||
|
|
[kSecClass as String: kSecClassGenericPassword,
|
||
|
|
kSecAttrService as String: "MusicBridge.connection.v1", kSecAttrAccount as String: "primaryPC"]
|
||
|
|
}
|
||
|
|
|
||
|
|
static func load() throws -> Connection? {
|
||
|
|
var q = query
|
||
|
|
q[kSecReturnData as String] = true
|
||
|
|
q[kSecMatchLimit as String] = kSecMatchLimitOne
|
||
|
|
var item: CFTypeRef?
|
||
|
|
let status = SecItemCopyMatching(q as CFDictionary, &item)
|
||
|
|
if status == errSecItemNotFound { return nil }
|
||
|
|
guard status == errSecSuccess, let data = item as? Data else { throw failure(status) }
|
||
|
|
let saved = try JSONDecoder().decode(Connection.self, from: data)
|
||
|
|
guard let token = saved.token, Connection.isFingerprint(token) else { throw BridgeError.message("Повреждена запись сопряжения.") }
|
||
|
|
return try Connection(endpoint: saved.endpoint.absoluteString, fingerprint: saved.fingerprint, token: token)
|
||
|
|
}
|
||
|
|
|
||
|
|
static func save(_ connection: Connection) throws {
|
||
|
|
let values: [String: Any] = [kSecValueData as String: try JSONEncoder().encode(connection),
|
||
|
|
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly]
|
||
|
|
var status = SecItemUpdate(query as CFDictionary, values as CFDictionary)
|
||
|
|
if status == errSecItemNotFound {
|
||
|
|
status = SecItemAdd(query.merging(values) { _, new in new } as CFDictionary, nil)
|
||
|
|
}
|
||
|
|
guard status == errSecSuccess else { throw failure(status) }
|
||
|
|
}
|
||
|
|
|
||
|
|
static func delete() throws {
|
||
|
|
let status = SecItemDelete(query as CFDictionary)
|
||
|
|
guard status == errSecSuccess || status == errSecItemNotFound else { throw failure(status) }
|
||
|
|
}
|
||
|
|
|
||
|
|
private static func failure(_ status: OSStatus) -> BridgeError {
|
||
|
|
.message("Не удалось прочитать или сохранить сопряжение в Keychain (\(status)).")
|
||
|
|
}
|
||
|
|
}
|