mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 16:06:32 +00:00
55 lines
2.0 KiB
Swift
55 lines
2.0 KiB
Swift
import Foundation
|
|
import Security
|
|
|
|
/// Items the app shares with this extension through a keychain access group
|
|
/// (BulwarkKeychainGroup in Info.plist). The app writes them with
|
|
/// expo-secure-store: generic passwords whose account and generic attributes
|
|
/// are the UTF-8 key and whose service is "app:no-auth".
|
|
enum SharedKeychain {
|
|
static let service = "app:no-auth"
|
|
|
|
static var group: String? {
|
|
Bundle.main.object(forInfoDictionaryKey: "BulwarkKeychainGroup") as? String
|
|
}
|
|
|
|
static func read(_ key: String) -> Data? {
|
|
guard let group else { return nil }
|
|
let account = Data(key.utf8)
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrAccount as String: account,
|
|
kSecAttrAccessGroup as String: group,
|
|
kSecMatchLimit as String: kSecMatchLimitOne,
|
|
kSecReturnData as String: true,
|
|
]
|
|
var item: CFTypeRef?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &item)
|
|
guard status == errSecSuccess else {
|
|
pushLog.error("keychain read of \(key, privacy: .public) failed: \(status, privacy: .public)")
|
|
return nil
|
|
}
|
|
return item as? Data
|
|
}
|
|
|
|
static func readJSON(_ key: String) -> [String: Any]? {
|
|
guard let data = read(key) else { return nil }
|
|
return (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
|
|
}
|
|
|
|
/// Replaces the value of an existing item (refreshed OAuth tokens). Never
|
|
/// creates one: the app owns which items exist.
|
|
@discardableResult
|
|
static func update(_ key: String, json: [String: Any]) -> Bool {
|
|
guard let group, let data = try? JSONSerialization.data(withJSONObject: json) else { return false }
|
|
let account = Data(key.utf8)
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: service,
|
|
kSecAttrAccount as String: account,
|
|
kSecAttrAccessGroup as String: group,
|
|
]
|
|
let attributes: [String: Any] = [kSecValueData as String: data]
|
|
return SecItemUpdate(query as CFDictionary, attributes as CFDictionary) == errSecSuccess
|
|
}
|
|
}
|