Skip to content

Commit dcd7e44

Browse files
committed
tmp: debug
1 parent 239fb83 commit dcd7e44

File tree

1 file changed

+156
-108
lines changed

1 file changed

+156
-108
lines changed

firefox-ios/Storage/Rust/RustLogins.swift

Lines changed: 156 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ import struct MozillaAppServices.Login
1818
import struct MozillaAppServices.LoginEntry
1919
import protocol MozillaAppServices.KeyManager
2020

21+
private let SecClass: String! = kSecClass as String
22+
private let SecAttrService: String! = kSecAttrService as String
23+
private let SecAttrGeneric: String! = kSecAttrGeneric as String
24+
private let SecAttrAccount: String! = kSecAttrAccount as String
25+
private let SecAttrSynchronizable: String = kSecAttrSynchronizable as String
26+
private let SecValueData: String! = kSecValueData as String
27+
private let SecAttrAccessible: String! = kSecAttrAccessible as String
28+
2129
typealias LoginsStoreError = LoginsApiError
2230
public typealias LoginRecord = Login
2331

@@ -218,18 +226,83 @@ public class RustLoginEncryptionKeys {
218226
self.logger = logger
219227
}
220228

229+
func debugKeychain(_ secret: String, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility) {
230+
guard let secretData = secret.data(using: .utf8) else {
231+
logger.log("[issam] 0 debugKeychain",
232+
level: .warning,
233+
category: .storage,
234+
description: "")
235+
return
236+
}
237+
238+
var keychainQueryDictionary: [String: Any] = [SecClass: kSecClassGenericPassword]
239+
240+
let serviceName = Bundle.main.bundleIdentifier ?? "SwiftKeychainWrapper"
241+
242+
logger.log("[issam] 1 debugKeychain",
243+
level: .warning,
244+
category: .storage,
245+
description: "\(serviceName)")
246+
247+
// Uniquely identify this keychain accessor
248+
keychainQueryDictionary[SecAttrService] = serviceName
249+
250+
// Uniquely identify the account who will be accessing the keychain
251+
let encodedIdentifier: Data? = key.data(using: String.Encoding.utf8)
252+
253+
keychainQueryDictionary[SecAttrGeneric] = encodedIdentifier
254+
255+
logger.log("[issam] 2 debugKeychain",
256+
level: .warning,
257+
category: .storage,
258+
description: "")
259+
260+
keychainQueryDictionary[SecAttrAccount] = encodedIdentifier
261+
262+
keychainQueryDictionary[SecAttrSynchronizable] = kCFBooleanFalse
263+
264+
let mzKeychainAttrMap: [MZKeychainItemAccessibility: CFString] = [
265+
.afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock,
266+
.afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
267+
// .always: kSecAttrAccessibleAlways,
268+
// .alwaysThisDeviceOnly: kSecAttrAccessibleAlwaysThisDeviceOnly,
269+
.whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
270+
.whenUnlocked: kSecAttrAccessibleWhenUnlocked,
271+
.whenUnlockedThisDeviceOnly: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
272+
]
273+
keychainQueryDictionary[SecAttrAccessible] = mzKeychainAttrMap[accessibility]
274+
keychainQueryDictionary[SecValueData] = secretData
275+
let status = SecItemAdd(keychainQueryDictionary as CFDictionary, nil)
276+
var errorMessage = "Unknown error (\(status))"
277+
if let message = SecCopyErrorMessageString(status, nil) {
278+
errorMessage = message as String
279+
}
280+
281+
logger.log("[issam] 3 debugKeychain",
282+
level: .warning,
283+
category: .storage,
284+
description: "SecItemAdd status: \(status) - \(errorMessage)")
285+
}
286+
221287
fileprivate func createAndStoreKey() throws -> String {
222288
do {
223289
let secret = try createKey()
224290
let canary = try createCanary(text: canaryPhrase, encryptionKey: secret)
225291

226292
DispatchQueue.global(qos: .background).sync {
227-
self.keychain.set(secret,
228-
forKey: self.loginPerFieldKeychainKey,
229-
withAccessibility: MZKeychainItemAccessibility.afterFirstUnlock)
293+
debugKeychain(secret,
294+
forKey: self.loginPerFieldKeychainKey,
295+
withAccessibility: MZKeychainItemAccessibility.afterFirstUnlock)
296+
let res = self.keychain.set(secret,
297+
forKey: self.loginPerFieldKeychainKey,
298+
withAccessibility: MZKeychainItemAccessibility.afterFirstUnlock)
230299
self.keychain.set(canary,
231300
forKey: self.canaryPhraseKey,
232301
withAccessibility: MZKeychainItemAccessibility.afterFirstUnlock)
302+
logger.log("[issam] keychain set result",
303+
level: .warning,
304+
category: .storage,
305+
description: "\(res)")
233306
}
234307
return secret
235308
} catch let err as NSError {
@@ -850,128 +923,97 @@ public class RustLogins: LoginsProtocol, KeyManager {
850923
}
851924
}
852925

853-
private func getKeychainData(rustKeys: RustLoginEncryptionKeys) -> (String?, String?) {
854-
var keychainData: (String?, String?) = (nil, nil)
855-
926+
private func getKeychainData(rustKeys: RustLoginEncryptionKeys, completion: @escaping (String?, String?) -> Void) {
856927
DispatchQueue.global(qos: .background).sync {
857928
let key = rustKeys.keychain.string(forKey: rustKeys.loginPerFieldKeychainKey)
858929
let encryptedCanaryPhrase = rustKeys.keychain.string(forKey: rustKeys.canaryPhraseKey)
859-
keychainData = (key, encryptedCanaryPhrase)
930+
completion(key, encryptedCanaryPhrase)
860931
}
861-
862-
return keychainData
863932
}
864933

865934
public func getStoredKey(completion: @escaping (Result<String, NSError>) -> Void) {
866935
let rustKeys = RustLoginEncryptionKeys()
867-
let (key, encryptedCanaryPhrase) = getKeychainData(rustKeys: rustKeys)
868-
switch(key, encryptedCanaryPhrase) {
869-
case (.some(key), .some(encryptedCanaryPhrase)):
870-
self.handleExpectedKeyAction(rustKeys: rustKeys,
871-
encryptedCanaryPhrase: encryptedCanaryPhrase,
872-
key: key,
873-
completion: completion)
874-
case (.some(key), .none):
875-
self.handleUnexpectedKeyAction(rustKeys: rustKeys, completion: completion)
876-
case (.none, .some(encryptedCanaryPhrase)):
877-
self.handleMissingKeyAction(rustKeys: rustKeys, completion: completion)
878-
case (.none, .none):
879-
self.handleFirstTimeCallOrClearedKeychainAction(rustKeys: rustKeys, completion: completion)
880-
default:
881-
self.handleIllegalStateAction(completion: completion)
882-
}
883-
}
884-
885-
private func handleExpectedKeyAction(rustKeys: RustLoginEncryptionKeys,
886-
encryptedCanaryPhrase: String?,
887-
key: String?,
888-
completion: @escaping (Result<String, NSError>) -> Void) {
889-
// We expected the key to be present, and it is.
890-
do {
891-
let canaryIsValid = try checkCanary(canary: encryptedCanaryPhrase!,
892-
text: rustKeys.canaryPhrase,
893-
encryptionKey: key!)
894-
if canaryIsValid {
895-
completion(.success(key!))
896-
} else {
897-
self.logger.log("Logins key was corrupted, new one generated",
936+
// swiftlint:disable:next closure_body_length
937+
getKeychainData(rustKeys: rustKeys) { (key, encryptedCanaryPhrase) in
938+
switch(key, encryptedCanaryPhrase) {
939+
case (.some(key), .some(encryptedCanaryPhrase)):
940+
// We expected the key to be present, and it is.
941+
do {
942+
let canaryIsValid = try checkCanary(canary: encryptedCanaryPhrase!,
943+
text: rustKeys.canaryPhrase,
944+
encryptionKey: key!)
945+
if canaryIsValid {
946+
completion(.success(key!))
947+
} else {
948+
self.logger.log("Logins key was corrupted, new one generated",
949+
level: .warning,
950+
category: .storage)
951+
GleanMetrics.LoginsStoreKeyRegeneration.corrupt.record()
952+
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
953+
}
954+
} catch let error as NSError {
955+
self.logger.log("Error validating logins encryption key",
956+
level: .warning,
957+
category: .storage,
958+
description: error.localizedDescription)
959+
completion(.failure(error))
960+
}
961+
case (.some(key), .none):
962+
// The key is present, but we didn't expect it to be there.
963+
964+
self.logger.log("Logins key lost due to storage malfunction, new one generated",
898965
level: .warning,
899966
category: .storage)
900-
GleanMetrics.LoginsStoreKeyRegeneration.corrupt.record()
967+
GleanMetrics.LoginsStoreKeyRegeneration.other.record()
901968
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
902-
}
903-
} catch let error as NSError {
904-
self.logger.log("Error validating logins encryption key",
905-
level: .warning,
906-
category: .storage,
907-
description: error.localizedDescription)
908-
completion(.failure(error))
909-
}
910-
}
911-
912-
private func handleUnexpectedKeyAction(rustKeys: RustLoginEncryptionKeys,
913-
completion: @escaping (Result<String, NSError>) -> Void) {
914-
// The key is present, but we didn't expect it to be there.
915-
916-
self.logger.log("Logins key lost due to storage malfunction, new one generated",
917-
level: .warning,
918-
category: .storage)
919-
GleanMetrics.LoginsStoreKeyRegeneration.other.record()
920-
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
921-
}
922-
923-
private func handleMissingKeyAction(rustKeys: RustLoginEncryptionKeys,
924-
completion: @escaping (Result<String, NSError>) -> Void) {
925-
// We expected the key to be present, but it's gone missing on us.
969+
case (.none, .some(encryptedCanaryPhrase)):
970+
// We expected the key to be present, but it's gone missing on us.
926971

927-
self.logger.log("Logins key lost, new one generated",
928-
level: .warning,
929-
category: .storage)
930-
GleanMetrics.LoginsStoreKeyRegeneration.lost.record()
931-
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
932-
}
933-
934-
private func handleFirstTimeCallOrClearedKeychainAction(rustKeys: RustLoginEncryptionKeys,
935-
completion: @escaping (Result<String, NSError>) -> Void) {
936-
// We didn't expect the key to be present, which either means this is a first-time
937-
// call or the key data has been cleared from the keychain.
972+
self.logger.log("Logins key lost, new one generated",
973+
level: .warning,
974+
category: .storage)
975+
GleanMetrics.LoginsStoreKeyRegeneration.lost.record()
976+
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
977+
case (.none, .none):
978+
// We didn't expect the key to be present, which either means this is a first-time
979+
// call or the key data has been cleared from the keychain.
938980

939-
self.hasSyncedLogins().upon { result in
940-
guard result.failureValue == nil else {
941-
completion(.failure(result.failureValue! as NSError))
942-
return
943-
}
981+
self.hasSyncedLogins().upon { result in
982+
guard result.failureValue == nil else {
983+
completion(.failure(result.failureValue! as NSError))
984+
return
985+
}
944986

945-
guard let hasLogins = result.successValue else {
946-
let msg = "Failed to verify logins count before attempting to reset key"
947-
completion(.failure(LoginEncryptionKeyError.dbRecordCountVerificationError(msg) as NSError))
948-
return
949-
}
987+
guard let hasLogins = result.successValue else {
988+
let msg = "Failed to verify logins count before attempting to reset key"
989+
completion(.failure(LoginEncryptionKeyError.dbRecordCountVerificationError(msg) as NSError))
990+
return
991+
}
950992

951-
if hasLogins {
952-
// Since the key data isn't present and we have login records in
953-
// the database, we both clear the database and reset the key.
954-
GleanMetrics.LoginsStoreKeyRegeneration.keychainDataLost.record()
955-
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
956-
} else {
957-
// There are no records in the database so we don't need to wipe any
958-
// existing login records. We just need to create a new key.
959-
do {
960-
let key = try rustKeys.createAndStoreKey()
961-
completion(.success(key))
962-
} catch let error as NSError {
963-
completion(.failure(error))
993+
if hasLogins {
994+
// Since the key data isn't present and we have login records in
995+
// the database, we both clear the database and reset the key.
996+
GleanMetrics.LoginsStoreKeyRegeneration.keychainDataLost.record()
997+
self.resetLoginsAndKey(rustKeys: rustKeys, completion: completion)
998+
} else {
999+
// There are no records in the database so we don't need to wipe any
1000+
// existing login records. We just need to create a new key.
1001+
do {
1002+
let key = try rustKeys.createAndStoreKey()
1003+
completion(.success(key))
1004+
} catch let error as NSError {
1005+
completion(.failure(error))
1006+
}
1007+
}
9641008
}
1009+
default:
1010+
// If none of the above cases apply, we're in a state that shouldn't be
1011+
// possible but is disallowed nonetheless
1012+
completion(.failure(LoginEncryptionKeyError.illegalState as NSError))
9651013
}
9661014
}
9671015
}
9681016

969-
private func handleIllegalStateAction(completion: @escaping (Result<String, NSError>) -> Void) {
970-
// If none of the above cases apply, we're in a state that shouldn't be
971-
// possible but is disallowed nonetheless
972-
completion(.failure(LoginEncryptionKeyError.illegalState as NSError))
973-
}
974-
9751017
// MARK: - KeyManager
9761018

9771019
/**
@@ -998,12 +1040,18 @@ public class RustLogins: LoginsProtocol, KeyManager {
9981040
*/
9991041
public func getKey() throws -> Data {
10001042
let rustKeys = RustLoginEncryptionKeys()
1001-
let (key, _) = getKeychainData(rustKeys: rustKeys)
10021043

1003-
guard let keyData = key?.data(using: .utf8) else {
1044+
guard let keyData = rustKeys.keychain.data(forKey: rustKeys.loginPerFieldKeychainKey) else {
1045+
logger.log("[issam] getKey 1 result",
1046+
level: .warning,
1047+
category: .storage,
1048+
description: "")
10041049
throw LoginsStoreError.MissingKey
10051050
}
1006-
1051+
logger.log("[issam] getKey 2 result",
1052+
level: .warning,
1053+
category: .storage,
1054+
description: "\(keyData.count)")
10071055
return keyData
10081056
}
10091057
}

0 commit comments

Comments
 (0)