mirror of
https://github.com/GLEGram/GLEGram-iOS.git
synced 2026-04-23 19:36:26 +02:00
4647310322
Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
117 lines
4.4 KiB
Swift
117 lines
4.4 KiB
Swift
// MARK: Swiftgram - Keychain storage for hidden-account passcodes (Double Bottom)
|
|
import Foundation
|
|
import Security
|
|
|
|
private let serviceName = "SwiftgramDoubleBottom"
|
|
|
|
/// Key for the single "secret" passcode (second password). When user unlocks with this, only one account is shown.
|
|
private let secretPasscodeAccountKey = "secret"
|
|
|
|
public enum DoubleBottomPasscodeStore {
|
|
// MARK: - Secret passcode (second password -> show only 1 account)
|
|
|
|
public static func setSecretPasscode(_ passcode: String) {
|
|
let data = passcode.data(using: .utf8)!
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: secretPasscodeAccountKey
|
|
]
|
|
var addQuery = query
|
|
addQuery[kSecValueData as String] = data
|
|
var status = SecItemAdd(addQuery as CFDictionary, nil)
|
|
if status == errSecDuplicateItem {
|
|
SecItemDelete(query as CFDictionary)
|
|
status = SecItemAdd(addQuery as CFDictionary, nil)
|
|
}
|
|
}
|
|
|
|
public static func secretPasscodeMatches(_ passcode: String) -> Bool {
|
|
guard let stored = secretPasscode() else { return false }
|
|
return stored == passcode
|
|
}
|
|
|
|
public static func hasSecretPasscode() -> Bool {
|
|
return secretPasscode() != nil
|
|
}
|
|
|
|
public static func removeSecretPasscode() {
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: secretPasscodeAccountKey
|
|
]
|
|
SecItemDelete(query as CFDictionary)
|
|
}
|
|
|
|
private static func secretPasscode() -> String? {
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: secretPasscodeAccountKey,
|
|
kSecReturnData as String: true,
|
|
kSecMatchLimit as String: kSecMatchLimitOne
|
|
]
|
|
var result: AnyObject?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
guard status == errSecSuccess, let data = result as? Data, let string = String(data: data, encoding: .utf8) else {
|
|
return nil
|
|
}
|
|
return string
|
|
}
|
|
|
|
// MARK: - Per-account passcodes (hidden accounts)
|
|
|
|
public static func setPasscode(_ passcode: String, forAccountId accountId: Int64) {
|
|
let account = "\(accountId)"
|
|
let data = passcode.data(using: .utf8)!
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: account
|
|
]
|
|
var addQuery = query
|
|
addQuery[kSecValueData as String] = data
|
|
var status = SecItemAdd(addQuery as CFDictionary, nil)
|
|
if status == errSecDuplicateItem {
|
|
SecItemDelete(query as CFDictionary)
|
|
status = SecItemAdd(addQuery as CFDictionary, nil)
|
|
}
|
|
}
|
|
|
|
public static func passcode(forAccountId accountId: Int64) -> String? {
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: "\(accountId)",
|
|
kSecReturnData as String: true,
|
|
kSecMatchLimit as String: kSecMatchLimitOne
|
|
]
|
|
var result: AnyObject?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
guard status == errSecSuccess, let data = result as? Data, let string = String(data: data, encoding: .utf8) else {
|
|
return nil
|
|
}
|
|
return string
|
|
}
|
|
|
|
public static func removePasscode(forAccountId accountId: Int64) {
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: serviceName,
|
|
kSecAttrAccount as String: "\(accountId)"
|
|
]
|
|
SecItemDelete(query as CFDictionary)
|
|
}
|
|
|
|
/// Returns the account id whose passcode matches the given value, or nil.
|
|
public static func accountId(matchingPasscode passcode: String, candidateIds: [Int64]) -> Int64? {
|
|
for id in candidateIds {
|
|
if Self.passcode(forAccountId: id) == passcode {
|
|
return id
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|