mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-29 04:39:53 +00:00
* core, iOS: support for self-destruct password * disable test logging * core: fix tests, iOS: remove notifications on removal * change alerts
119 lines
3.7 KiB
Swift
119 lines
3.7 KiB
Swift
//
|
|
// KeyChain.swift
|
|
// SimpleXChat
|
|
//
|
|
// Created by Evgeny on 04/09/2022.
|
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Security
|
|
|
|
private let ACCESS_POLICY: CFString = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
private let ACCESS_GROUP: String = "5NN7GUYB6T.chat.simplex.app"
|
|
private let DATABASE_PASSWORD_ITEM: String = "databasePassword"
|
|
private let APP_PASSWORD_ITEM: String = "appPassword"
|
|
private let SELF_DESTRUCT_PASSWORD_ITEM: String = "selfDestructPassword"
|
|
|
|
public let kcDatabasePassword = KeyChainItem(forKey: DATABASE_PASSWORD_ITEM)
|
|
|
|
public let kcAppPassword = KeyChainItem(forKey: APP_PASSWORD_ITEM)
|
|
|
|
public let kcSelfDestructPassword = KeyChainItem(forKey: SELF_DESTRUCT_PASSWORD_ITEM)
|
|
|
|
public struct KeyChainItem {
|
|
var forKey: String
|
|
|
|
public func get() -> String? {
|
|
getItemString(forKey: forKey)
|
|
}
|
|
|
|
public func set(_ value: String) -> Bool {
|
|
setItemString(value, forKey: forKey)
|
|
}
|
|
|
|
public func remove() -> Bool {
|
|
deleteItem(forKey: forKey)
|
|
}
|
|
}
|
|
|
|
func randomDatabasePassword() -> String {
|
|
var keyData = Data(count: 32)
|
|
let status = keyData.withUnsafeMutableBytes {
|
|
SecRandomCopyBytes(kSecRandomDefault, 32, $0.baseAddress!)
|
|
}
|
|
if status == errSecSuccess {
|
|
return keyData.base64EncodedString()
|
|
} else {
|
|
logger.error("randomDatabasePassword: error \(status)")
|
|
return ""
|
|
}
|
|
}
|
|
|
|
private func getItemData(forKey key: String) -> Data? {
|
|
var query = baseItemQuery(forKey: key)
|
|
query[kSecMatchLimit] = kSecMatchLimitOne
|
|
query[kSecReturnData] = true as AnyObject?
|
|
|
|
var dataRef: CFTypeRef?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &dataRef)
|
|
if status != errSecSuccess && status != errSecItemNotFound {
|
|
logger.error("getItemData: error getting data for key '\(key)', error: \(status)")
|
|
}
|
|
return dataRef as? Data
|
|
}
|
|
|
|
private func getItemString(forKey key: String) -> String? {
|
|
if let data = getItemData(forKey: key) {
|
|
return NSString(data: data, encoding: String.Encoding.utf8.rawValue) as? String
|
|
}
|
|
return nil
|
|
}
|
|
|
|
private func setItemData(_ data: Data, forKey key: String) -> Bool {
|
|
var query = baseItemQuery(forKey: key)
|
|
var update = [NSString : AnyObject]()
|
|
update[kSecValueData] = data as AnyObject?
|
|
update[kSecAttrAccessible] = ACCESS_POLICY
|
|
var status: OSStatus
|
|
if getItemData(forKey: key) == nil {
|
|
for (key, value) in update { query[key] = value }
|
|
status = SecItemAdd(query as CFDictionary, nil)
|
|
} else {
|
|
status = SecItemUpdate(query as CFDictionary, update as CFDictionary)
|
|
}
|
|
if status != errSecSuccess {
|
|
logger.error("setItemData: error setting data for key '\(key)', error: \(status)")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func setItemString(_ s: String, forKey key: String) -> Bool {
|
|
if let data = s.data(using: .utf8) {
|
|
return setItemData(data, forKey: key)
|
|
}
|
|
return false
|
|
}
|
|
|
|
private func deleteItem(forKey key: String) -> Bool {
|
|
let query = baseItemQuery(forKey: key)
|
|
if getItemData(forKey: key) != nil {
|
|
let status = SecItemDelete(query as CFDictionary)
|
|
if status != errSecSuccess {
|
|
logger.error("deleteItem: error deleting data for key '\(key)', error: \(status)")
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func baseItemQuery(forKey key: String) -> [NSString : AnyObject] {
|
|
var query = [NSString : AnyObject]()
|
|
query[kSecClass] = kSecClassGenericPassword
|
|
query[kSecAttrAccount] = key as AnyObject?
|
|
#if TARGET_OS_IOS && !TARGET_OS_SIMULATOR
|
|
query[kSecAttrAccessGroup] = ACCESS_GROUP
|
|
#endif
|
|
return query
|
|
}
|