tokenary/Encrypted Ink/Services/Keychain.swift
2021-06-19 21:20:42 +03:00

67 lines
2.1 KiB
Swift

// Copyright © 2021 Encrypted Ink. All rights reserved.
import Foundation
struct Keychain {
private static let prefix = "ink.encrypted.macos."
private enum Key: String {
case accounts = "ethereum.keys"
case password = "password"
}
static var password: String? {
if let data = get(key: .password), let password = String(data: data, encoding: .utf8) {
return password
} else {
return nil
}
}
static func save(password: String) {
guard let data = password.data(using: .utf8) else { return }
save(data: data, key: .password)
}
static var accounts: [Account] {
if let data = get(key: .accounts), let accounts = try? JSONDecoder().decode([Account].self, from: data) {
return accounts
} else {
return []
}
}
static func save(accounts: [Account]) {
guard let data = try? JSONEncoder().encode(accounts) else { return }
save(data: data, key: .accounts)
}
// MARK: Private
private static func save(data: Data, key: Key) {
let query = [kSecClass as String: kSecClassGenericPassword as String,
kSecAttrAccount as String: prefix + key.rawValue,
kSecValueData as String: data] as [String: Any]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
private static func get(key: Key) -> Data? {
guard let returnDataQueryValue = kCFBooleanTrue else { return nil }
let query = [kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: prefix + key.rawValue,
kSecReturnData as String: returnDataQueryValue,
kSecMatchLimit as String: kSecMatchLimitOne] as [String: Any]
var dataTypeRef: AnyObject?
let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
if status == noErr, let data = dataTypeRef as? Data {
return data
} else {
return nil
}
}
}