diff --git a/FlowCrypt.xcodeproj/project.pbxproj b/FlowCrypt.xcodeproj/project.pbxproj index 17812f76d..f26339d20 100644 --- a/FlowCrypt.xcodeproj/project.pbxproj +++ b/FlowCrypt.xcodeproj/project.pbxproj @@ -185,7 +185,6 @@ 9FC41183268118B1004C0A69 /* EmailProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EBC1266EBE0100F3BF5D /* EmailProviderMock.swift */; }; 9FC413182683C492004C0A69 /* InMemoryPassPhraseStorageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC413172683C491004C0A69 /* InMemoryPassPhraseStorageTest.swift */; }; 9FC413442683C912004C0A69 /* GmailServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC413432683C912004C0A69 /* GmailServiceTest.swift */; }; - 9FC7EAB3266A404D00F3BF5D /* PassPhraseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */; }; 9FC7EB76266EB67B00F3BF5D /* EncryptedStorageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EB75266EB67B00F3BF5D /* EncryptedStorageProtocols.swift */; }; 9FC7EBAA266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC7EBA9266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift */; }; 9FD364862381EFCB00657302 /* SetupManuallyEnterPassPhraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD364852381EFCB00657302 /* SetupManuallyEnterPassPhraseViewController.swift */; }; @@ -611,7 +610,6 @@ 9FC411892681191D004C0A69 /* PromiseTestExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromiseTestExtension.swift; sourceTree = ""; }; 9FC413172683C491004C0A69 /* InMemoryPassPhraseStorageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryPassPhraseStorageTest.swift; sourceTree = ""; }; 9FC413432683C912004C0A69 /* GmailServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GmailServiceTest.swift; sourceTree = ""; }; - 9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassPhraseObject.swift; sourceTree = ""; }; 9FC7EB75266EB67B00F3BF5D /* EncryptedStorageProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptedStorageProtocols.swift; sourceTree = ""; }; 9FC7EBA2266EB95300F3BF5D /* PassPhraseStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassPhraseStorageTests.swift; sourceTree = ""; }; 9FC7EBA9266EBD3700F3BF5D /* InMemoryPassPhraseStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryPassPhraseStorage.swift; sourceTree = ""; }; @@ -1088,7 +1086,6 @@ 9F1B49E02624E19D00420472 /* Realm Models */ = { isa = PBXGroup; children = ( - 9FC7EAB2266A404D00F3BF5D /* PassPhraseObject.swift */, D2F41372243CC7990066AFB5 /* UserObject.swift */, D27B911C24EFE806002DF0A1 /* ContactObject.swift */, D2E26F6924F25AB800612AF1 /* KeyAlgoObject.swift */, @@ -2684,7 +2681,6 @@ D29AFFF92409767F00C1387D /* GoogleContactsResponse.swift in Sources */, 9F003D6125E1B4ED00EB38C0 /* TrashFolderProvider.swift in Sources */, 9FF0671025520D7100FCC9E6 /* MessageGateway.swift in Sources */, - 9FC7EAB3266A404D00F3BF5D /* PassPhraseObject.swift in Sources */, 9F31AB8C23298B3F00CF87EA /* Imap+retry.swift in Sources */, 9F79229426696B9300DA3D80 /* KeyDataStorage.swift in Sources */, 9F82D352256D74FA0069A702 /* InboxViewContainerController.swift in Sources */, diff --git a/FlowCrypt/Controllers/Setup/SetupBackupsViewController.swift b/FlowCrypt/Controllers/Setup/SetupBackupsViewController.swift index b12ead124..3df8241e8 100644 --- a/FlowCrypt/Controllers/Setup/SetupBackupsViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupBackupsViewController.swift @@ -144,17 +144,22 @@ extension SetupBackupsViewController { return } - // save pass phrase - matchingKeyBackups - .map { - PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) - } - .forEach { - passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase) - } + if !shouldStorePassPhrase { + // save pass phrase + matchingKeyBackups + .map { + PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) + } + .forEach { + passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase) + } + } // save keys - keyStorage.addKeys(keyDetails: Array(matchingKeyBackups), source: .backup, for: user.email) + keyStorage.addKeys(keyDetails: Array(matchingKeyBackups), + passPhrase: shouldStorePassPhrase ? passPhrase : nil, + source: .backup, + for: user.email) moveToMainFlow() } diff --git a/FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift b/FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift index 4e092c59f..5877cfd72 100644 --- a/FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupEKMKeyViewController.swift @@ -87,12 +87,18 @@ extension SetupEKMKeyViewController { passphrase: passPhrase ) let parsedKey = try self.core.parseKeys(armoredOrBinary: encryptedPrv.encryptedKey.data()) - self.keyStorage.addKeys(keyDetails: parsedKey.keyDetails, source: .ekm, for: self.user.email) + self.keyStorage.addKeys(keyDetails: parsedKey.keyDetails, + passPhrase: self.shouldStorePassPhrase ? passPhrase : nil, + source: .ekm, + for: self.user.email) allFingerprints.append(contentsOf: parsedKey.keyDetails.flatMap { $0.fingerprints }) } } - let passPhrase = PassPhrase(value: passPhrase, fingerprints: allFingerprints.unique()) - self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase) + + if !self.shouldStorePassPhrase { + let passPhrase = PassPhrase(value: passPhrase, fingerprints: allFingerprints.unique()) + self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase) + } } .then(on: .main) { [weak self] in self?.hideSpinner() diff --git a/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift b/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift index 85eccc497..da33a4a76 100644 --- a/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift @@ -87,10 +87,15 @@ extension SetupGenerateKeyViewController { try awaitPromise(self.backupService.backupToInbox(keys: [encryptedPrv.key], for: self.user)) - let passPhrase = PassPhrase(value: passPhrase, fingerprints: encryptedPrv.key.fingerprints) - - self.keyStorage.addKeys(keyDetails: [encryptedPrv.key], source: .generated, for: self.user.email) - self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: self.shouldStorePassPhrase) + self.keyStorage.addKeys(keyDetails: [encryptedPrv.key], + passPhrase: self.shouldStorePassPhrase ? passPhrase: nil, + source: .generated, + for: self.user.email) + + if !self.shouldStorePassPhrase { + let passPhrase = PassPhrase(value: passPhrase, fingerprints: encryptedPrv.key.fingerprints) + self.passPhraseService.savePassPhrase(with: passPhrase, inStorage: false) + } let updateKey = self.attester.updateKey( email: userId.email, diff --git a/FlowCrypt/Controllers/Setup/SetupManuallyEnterPassPhraseViewController.swift b/FlowCrypt/Controllers/Setup/SetupManuallyEnterPassPhraseViewController.swift index e24bedc9f..f0c9f2a08 100644 --- a/FlowCrypt/Controllers/Setup/SetupManuallyEnterPassPhraseViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupManuallyEnterPassPhraseViewController.swift @@ -241,24 +241,27 @@ extension SetupManuallyEnterPassPhraseViewController { let keysToUpdate = Array(Set(existedKeys).intersection(fetchedKeys)) let newKeysToAdd = Array(Set(fetchedKeys).subtracting(existedKeys)) - keysStorage.addKeys(keyDetails: newKeysToAdd, source: .imported, for: email) - keysStorage.updateKeys(keyDetails: keysToUpdate, source: .imported, for: email) + keysStorage.addKeys(keyDetails: newKeysToAdd, passPhrase: passPhrase, source: .imported, for: email) + keysStorage.updateKeys(keyDetails: keysToUpdate, passPhrase: passPhrase, source: .imported, for: email) - keysToUpdate - .map { - PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) - } - .forEach { - passPhraseService.updatePassPhrase(with: $0, inStorage: shouldStorePassPhrase) - } + if !shouldStorePassPhrase { + keysToUpdate + .map { + PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) + } + .forEach { + passPhraseService.updatePassPhrase(with: $0, inStorage: shouldStorePassPhrase) + } + + newKeysToAdd + .map { + PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) + } + .forEach { + passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase) + } + } - newKeysToAdd - .map { - PassPhrase(value: passPhrase, fingerprints: $0.fingerprints) - } - .forEach { - passPhraseService.savePassPhrase(with: $0, inStorage: shouldStorePassPhrase) - } hideSpinner() diff --git a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift index b211983fb..3be3512c4 100644 --- a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift +++ b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift @@ -110,8 +110,6 @@ extension EncryptedStorage: LogOutHandler { .filter { $0.email == email } let keys = storage.objects(KeyInfo.self) .filter { $0.account == email } - let passPhrases = storage.objects(PassPhraseObject.self) - .filter { keys.map(\.primaryFingerprint).contains($0.primaryFingerprint) } let sessions = storage.objects(SessionObject.self) .filter { $0.email == email } let clientConfigurations = storage.objects(ClientConfigurationObject.self) @@ -120,7 +118,6 @@ extension EncryptedStorage: LogOutHandler { try storage.write { storage.delete(keys) storage.delete(sessions) - storage.delete(passPhrases) storage.delete(clientConfigurations) storage.delete(userToDelete) } @@ -159,30 +156,39 @@ extension EncryptedStorage { // MARK: - Keys extension EncryptedStorage { - func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { + func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { guard let user = storage.objects(UserObject.self).first(where: { $0.email == email }) else { logger.logError("Can't find user with given email to add keys. User should be already saved") return } try! storage.write { for key in keyDetails { - storage.add(try! KeyInfo(key, source: source, user: user)) + storage.add(try! KeyInfo(key, passphrase: passPhrase, source: source, user: user)) } } } - func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { + func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { guard let user = getUserObject(for: email) else { logger.logError("Can't find user with given email to update keys. User should be already saved") return } try! storage.write { for key in keyDetails { - storage.add(try! KeyInfo(key, source: source, user: user), update: .all) + storage.add(try! KeyInfo(key, passphrase: passPhrase, source: source, user: user), update: .all) } } } + func updateKeys(with primaryFingerprint: String, passphrase: String?) { + let keys = keysInfo() + .filter { $0.primaryFingerprint == primaryFingerprint } + + try! storage.write { + keys.map { $0.passphrase = passphrase } + } + } + func keysInfo() -> [KeyInfo] { let result = storage.objects(KeyInfo.self) return Array(result) @@ -209,25 +215,19 @@ extension EncryptedStorage { // MARK: - PassPhrase extension EncryptedStorage: PassPhraseStorageType { func save(passPhrase: PassPhrase) { - try! storage.write { - storage.add(PassPhraseObject(passPhrase)) - } + updateKeys(with: passPhrase.primaryFingerprint, passphrase: passPhrase.value) } func update(passPhrase: PassPhrase) { - try! storage.write { - storage.add(PassPhraseObject(passPhrase), update: .all) - } + updateKeys(with: passPhrase.primaryFingerprint, passphrase: passPhrase.value) } func remove(passPhrase: PassPhrase) { - try! storage.write { - storage.delete(PassPhraseObject(passPhrase)) - } + updateKeys(with: passPhrase.primaryFingerprint, passphrase: nil) } func getPassPhrases() -> [PassPhrase] { - Array(storage.objects(PassPhraseObject.self)).map(PassPhrase.init) + keysInfo().compactMap(PassPhrase.init) } } diff --git a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorageProtocols.swift b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorageProtocols.swift index 046f7773b..ca44fef12 100644 --- a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorageProtocols.swift +++ b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorageProtocols.swift @@ -9,8 +9,8 @@ import Foundation protocol KeyStorageType { - func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) - func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) + func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) + func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) func publicKey() -> String? func keysInfo() -> [KeyInfo] } diff --git a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+Other.swift b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+Other.swift index 30a41a83c..c0917f73d 100644 --- a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+Other.swift +++ b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+Other.swift @@ -46,7 +46,7 @@ extension Imap { self.fetchMessage(in: folder, kind: kind, uids: uids) }) else { return } - guard let messages = msgs as? [MCOIMAPMessage] else { + guard let messages = msgs else { return reject(AppErr.cast("[MCOIMAPMessage]")) } return resolve(messages) diff --git a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+messages.swift b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+messages.swift index 340212bd6..b8d5e64ae 100644 --- a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+messages.swift +++ b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+messages.swift @@ -27,7 +27,7 @@ extension Imap { .start { error, messages, _ in // original method sig has 3 args, finalize expects 2 args self.finalize("fetchMsgsByNumber", resolve, reject, retry: { self.fetchMsgsByNumber(for: folder, kind: kind, set: set) - })(error, messages as? [MCOIMAPMessage]) + })(error, messages) } } } @@ -49,7 +49,7 @@ extension Imap { .start { error, messages, _ in // original method sig has 3 args, finalize expects 2 args self.finalize("fetchMessagesByUIDOperation", resolve, reject, retry: { self.fetchMessagesByUIDOperation(for: folder, kind: kind, set: set) - })(error, messages as? [MCOIMAPMessage]) + })(error, messages) } } } diff --git a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift index e45108369..9a47cb026 100644 --- a/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift +++ b/FlowCrypt/Functionality/Mail Provider/Imap/Imap+session.swift @@ -83,7 +83,7 @@ extension Imap { extension MCOIMAPSession { func log() -> Self { - connectionLogger = { connectionID, type, data in + connectionLogger = { _, type, data in guard let data = data, let string = String(data: data, encoding: .utf8) else { return } Logger.nested("IMAP").logInfo("\(type):\(string)") } @@ -93,7 +93,7 @@ extension MCOIMAPSession { extension MCOSMTPSession { func log() -> Self { - connectionLogger = { connectionID, type, data in + connectionLogger = { _, type, data in guard let data = data, let string = String(data: data, encoding: .utf8) else { return } Logger.nested("SMTP").logInfo("\(type):\(string)") } diff --git a/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/Imap+folders.swift b/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/Imap+folders.swift index 3c974e57a..e6efba8a3 100644 --- a/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/Imap+folders.swift +++ b/FlowCrypt/Functionality/Services/Folders Services/RemoteFoldersProviderType/Imap+folders.swift @@ -25,7 +25,7 @@ extension Imap: RemoteFoldersProviderType { reject(ImapError.providerError(error)) return } - guard let folders = value as? [MCOIMAPFolder] else { + guard let folders = value else { return reject(AppErr.cast("[MCOIMAPFolder]")) } diff --git a/FlowCrypt/Functionality/Services/Key Services/KeyDataStorage.swift b/FlowCrypt/Functionality/Services/Key Services/KeyDataStorage.swift index 42f01c647..d92cf1369 100644 --- a/FlowCrypt/Functionality/Services/Key Services/KeyDataStorage.swift +++ b/FlowCrypt/Functionality/Services/Key Services/KeyDataStorage.swift @@ -22,8 +22,8 @@ final class KeyDataStorage { } extension KeyDataStorage: KeyStorageType { - func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { - encryptedStorage.updateKeys(keyDetails: keyDetails, source: source, for: email) + func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { + encryptedStorage.updateKeys(keyDetails: keyDetails, passPhrase: passPhrase, source: source, for: email) } func publicKey() -> String? { @@ -34,7 +34,7 @@ extension KeyDataStorage: KeyStorageType { encryptedStorage.keysInfo() } - func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { - encryptedStorage.addKeys(keyDetails: keyDetails, source: source, for: email) + func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { + encryptedStorage.addKeys(keyDetails: keyDetails, passPhrase: passPhrase, source: source, for: email) } } diff --git a/FlowCrypt/Functionality/Services/Key Services/KeyService.swift b/FlowCrypt/Functionality/Services/Key Services/KeyService.swift index f2b11b1a0..b35accdbc 100644 --- a/FlowCrypt/Functionality/Services/Key Services/KeyService.swift +++ b/FlowCrypt/Functionality/Services/Key Services/KeyService.swift @@ -100,19 +100,19 @@ final class KeyService: KeyServiceType { } // append keys to ensure with a pass phrase - if let passPhrase = passPhrase { - let keysToEnsure = keysInfo.map { - PrvKeyInfo( - private: $0.private, - longid: $0.primaryLongid, - passphrase: passPhrase, - fingerprints: Array($0.allFingerprints) - ) - } - - privateKeys.append(contentsOf: keysToEnsure) + let keysToEnsure: [PrvKeyInfo] = keysInfo.compactMap { + guard let passPhraseValue = $0.passphrase ?? passPhrase else { return nil } + + return PrvKeyInfo( + private: $0.private, + longid: $0.primaryLongid, + passphrase: passPhraseValue, + fingerprints: Array($0.allFingerprints) + ) } + privateKeys.append(contentsOf: keysToEnsure) + return .success(privateKeys) } } diff --git a/FlowCrypt/Functionality/Services/Key Services/PassPhraseService.swift b/FlowCrypt/Functionality/Services/Key Services/PassPhraseService.swift index 63b51993b..fdfee264b 100644 --- a/FlowCrypt/Functionality/Services/Key Services/PassPhraseService.swift +++ b/FlowCrypt/Functionality/Services/Key Services/PassPhraseService.swift @@ -38,6 +38,15 @@ struct PassPhrase: Codable, Hashable, Equatable { } } +extension PassPhrase { + init?(keyInfo: KeyInfo) { + guard let passphrase = keyInfo.passphrase else { return nil } + + self.init(value: passphrase, + fingerprints: Array(keyInfo.allFingerprints)) + } +} + // MARK: - Pass Phrase Storage protocol PassPhraseStorageType { func save(passPhrase: PassPhrase) diff --git a/FlowCrypt/Models/Realm Models/KeyInfo.swift b/FlowCrypt/Models/Realm Models/KeyInfo.swift index a0d65c50c..ca7880bdc 100644 --- a/FlowCrypt/Models/Realm Models/KeyInfo.swift +++ b/FlowCrypt/Models/Realm Models/KeyInfo.swift @@ -31,10 +31,11 @@ final class KeyInfo: Object { let allFingerprints = List() let allLongids = List() + @objc dynamic var passphrase: String? @objc dynamic var source: String = "" @objc dynamic var user: UserObject! - convenience init(_ keyDetails: KeyDetails, source: KeySource, user: UserObject) throws { + convenience init(_ keyDetails: KeyDetails, passphrase: String?, source: KeySource, user: UserObject) throws { self.init() guard let privateKey = keyDetails.private else { @@ -51,6 +52,7 @@ final class KeyInfo: Object { self.`public` = keyDetails.public self.allFingerprints.append(objectsIn: keyDetails.ids.map(\.fingerprint)) self.allLongids.append(objectsIn: keyDetails.ids.map(\.longid)) + self.passphrase = passphrase self.source = source.rawValue self.user = user } diff --git a/FlowCrypt/Models/Realm Models/PassPhraseObject.swift b/FlowCrypt/Models/Realm Models/PassPhraseObject.swift deleted file mode 100644 index 78f1443f2..000000000 --- a/FlowCrypt/Models/Realm Models/PassPhraseObject.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// PassPhraseInfo.swift -// FlowCrypt -// -// Created by Anton Kharchevskyi on 04.06.2021. -// Copyright © 2017-present FlowCrypt a. s. All rights reserved. -// - -import Foundation -import RealmSwift - -/// PassPhrase object to store in Realm -final class PassPhraseObject: Object { - @objc dynamic var value: String = "" - let allFingerprints = List() - - convenience init( - value: String = "", - fingerprints: [String] - ) { - self.init() - self.value = value - self.allFingerprints.append(objectsIn: fingerprints) - } - - override class func primaryKey() -> String? { - "value" - } -} - -// MARK: - Convenience -extension PassPhraseObject { - var primaryFingerprint: String { - allFingerprints[0] - } - - convenience init(_ passPhrase: PassPhrase) { - self.init(value: passPhrase.value, fingerprints: passPhrase.fingerprints) - } -} - -extension PassPhrase { - init(object: PassPhraseObject) { - self.value = object.value - self.fingerprints = Array(object.allFingerprints) - self.date = nil - } -} diff --git a/FlowCryptAppTests/Core/Models/KeyInfoTests.swift b/FlowCryptAppTests/Core/Models/KeyInfoTests.swift index bb6235392..f21ee1605 100644 --- a/FlowCryptAppTests/Core/Models/KeyInfoTests.swift +++ b/FlowCryptAppTests/Core/Models/KeyInfoTests.swift @@ -28,7 +28,7 @@ class KeyInfoTests: XCTestCase { ) var thrownError: Error? - XCTAssertThrowsError(try KeyInfo(keyDetail, source: .backup, user: user)) { error in + XCTAssertThrowsError(try KeyInfo(keyDetail, passphrase: nil, source: .backup, user: user)) { error in thrownError = error } @@ -50,7 +50,7 @@ class KeyInfoTests: XCTestCase { ) var thrownError: Error? - XCTAssertThrowsError(try KeyInfo(keyDetail, source: .backup, user: user)) { error in + XCTAssertThrowsError(try KeyInfo(keyDetail, passphrase: nil, source: .backup, user: user)) { error in thrownError = error } @@ -70,7 +70,7 @@ class KeyInfoTests: XCTestCase { ) var thrownError: Error? - XCTAssertThrowsError(try KeyInfo(keyDetail, source: .backup, user: user)) { error in + XCTAssertThrowsError(try KeyInfo(keyDetail, passphrase: nil, source: .backup, user: user)) { error in thrownError = error } @@ -93,12 +93,13 @@ class KeyInfoTests: XCTestCase { algo: nil ) - let key = try KeyInfo(keyDetail, source: .backup, user: user) + let key = try KeyInfo(keyDetail, passphrase: "123", source: .backup, user: user) XCTAssertTrue(key.private == "private") XCTAssertTrue(key.public == "public") XCTAssertTrue(Array(key.allFingerprints) == ["f1", "f2", "f3"]) XCTAssertTrue(Array(key.allLongids) == ["l1", "l2", "l3"]) + XCTAssertTrue(key.passphrase == "123") XCTAssertTrue(key.source == "backup") XCTAssertTrue(key.user == user) XCTAssertTrue(key.primaryFingerprint == "f1") diff --git a/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/InMemoryPassPhraseStorageTest.swift b/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/InMemoryPassPhraseStorageTest.swift index 8b5bf3d3a..7f034f1a7 100644 --- a/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/InMemoryPassPhraseStorageTest.swift +++ b/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/InMemoryPassPhraseStorageTest.swift @@ -30,7 +30,7 @@ class InMemoryPassPhraseStorageTest: XCTestCase { XCTAssertNotNil($0.date) } } - + func testUpdatePassPhraseUpdatesDate() { let pass = PassPhrase(value: "A", fingerprints: ["11","12"]) sut.update(passPhrase: pass) @@ -38,7 +38,7 @@ class InMemoryPassPhraseStorageTest: XCTestCase { XCTAssertNotNil($0.date) } } - + func testRemovePassPhrase() { let pass = PassPhrase(value: "A", fingerprints: ["11","12"]) sut.save(passPhrase: pass) @@ -73,7 +73,7 @@ class InMemoryPassPhraseProviderMock: InMemoryPassPhraseProviderType { func save(passPhrase: PassPhrase) { passPhrases.insert(passPhrase) } - + func removePassPhrases(with objects: PassPhrase) { if passPhrases.contains(objects) { passPhrases.remove(objects) diff --git a/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/PassPhraseStorageTests.swift b/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/PassPhraseStorageTests.swift index 68d3adccc..298460ce2 100644 --- a/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/PassPhraseStorageTests.swift +++ b/FlowCryptAppTests/Functionality/Services/PassPhraseStorageTests/PassPhraseStorageTests.swift @@ -10,35 +10,35 @@ import XCTest @testable import FlowCrypt class PassPhraseStorageTests: XCTestCase { - + var sut: PassPhraseService! var encryptedStorage: PassPhraseStorageMock! var inMemoryStorage: PassPhraseStorageMock! var emailProvider: EmailProviderMock! - + override func setUp() { emailProvider = EmailProviderMock() encryptedStorage = PassPhraseStorageMock() inMemoryStorage = PassPhraseStorageMock() - + sut = PassPhraseService( encryptedStorage: encryptedStorage, localStorage: inMemoryStorage, emailProvider: emailProvider ) } - + func testGetPassPhrasesWhenEmpty() { // no pass phrases in storage encryptedStorage.getPassPhrasesResult = { [] } // no pass phrases in localStorage inMemoryStorage.getPassPhrasesResult = { [] } - + let result = sut.getPassPhrases() - + XCTAssertTrue(result.isEmpty) } - + func testGetValidPassPhraseFromStorage() { let passPhrase1 = PassPhrase( value: "some", @@ -48,27 +48,27 @@ class PassPhraseStorageTests: XCTestCase { value: "some", fingerprints: ["21","22"] ) - + encryptedStorage.getPassPhrasesResult = { [passPhrase1] } // no pass phrases in localStorage inMemoryStorage.getPassPhrasesResult = { [] } - + var result = sut.getPassPhrases() - + XCTAssertTrue(result.count == 1) - + encryptedStorage.getPassPhrasesResult = { [passPhrase1, passPhrase2] } - + result = sut.getPassPhrases() - + XCTAssertTrue(result.count == 2) } - + func testGetValidPassPhraseInLocalStorage() { encryptedStorage.getPassPhrasesResult = { [] } - + let savedDate = Date() let localPassPhrase = PassPhrase( value: "value", @@ -76,14 +76,14 @@ class PassPhraseStorageTests: XCTestCase { date: savedDate ) inMemoryStorage.getPassPhrasesResult = { [localPassPhrase] } - + // current timeout = 2 sleep(1) - + let result = sut.getPassPhrases() XCTAssertTrue(result.isNotEmpty) } - + func testBothStorageContainsValidPassPhrase() { let passPhrase1 = PassPhrase( value: "some", @@ -96,66 +96,66 @@ class PassPhraseStorageTests: XCTestCase { encryptedStorage.getPassPhrasesResult = { [passPhrase1, passPhrase2] } - + let savedDate = Date() let localPassPhrase = PassPhrase( value: "value", fingerprints: ["123444"], date: savedDate ) - + inMemoryStorage.getPassPhrasesResult = { [localPassPhrase] } - + let result = sut.getPassPhrases() XCTAssertTrue(result.count == 3) } - + func testSavePassPhraseInStorage() { let passPhraseToSave = PassPhrase(value: "pass", fingerprints: ["fingerprint 1", "123333"]) - + let expectation = XCTestExpectation() expectation.expectedFulfillmentCount = 1 expectation.isInverted = true - + // encrypted storage contains pass phrase which should be saved locally encryptedStorage.getPassPhrasesResult = { [ PassPhrase(value: "pass", fingerprints: ["fingerprint 1", "adfnhjfg"]) ] } - - + + // encrypted storage should not contains pass phrase which user decide to save locally encryptedStorage.isRemovePassPhraseResult = { passPhraseToRemove in if passPhraseToRemove.primaryFingerprint == "fingerprint 1" { expectation.fulfill() } } - + sut.savePassPhrase(with: passPhraseToSave, inStorage: true) - + XCTAssertFalse(inMemoryStorage.saveResult != nil ) - + wait(for: [expectation], timeout: 0.1, enforceOrder: false) } - + func testSavePassPhraseInStorageWithoutAnyPassPhrases() { let passPhraseToSave = PassPhrase(value: "pass", fingerprints: ["fingerprint 1", "123333"]) - + let expectation = XCTestExpectation() expectation.isInverted = true - + // encrypted storage is empty encryptedStorage.getPassPhrasesResult = { [ ] } - + encryptedStorage.isRemovePassPhraseResult = { _ in expectation.fulfill() } - + sut.savePassPhrase(with: passPhraseToSave, inStorage: true) - + XCTAssertFalse(inMemoryStorage.saveResult != nil ) - + wait(for: [expectation], timeout: 0.1, enforceOrder: false) } @@ -181,6 +181,7 @@ extension KeyInfo { users: [], algo: nil ), + passphrase: nil, source: .backup, user: UserObject( name: "name", diff --git a/FlowCryptAppTests/Mocks/KeyStorageMock.swift b/FlowCryptAppTests/Mocks/KeyStorageMock.swift index a3bfa3191..d651ace5f 100644 --- a/FlowCryptAppTests/Mocks/KeyStorageMock.swift +++ b/FlowCryptAppTests/Mocks/KeyStorageMock.swift @@ -10,11 +10,11 @@ import Foundation @testable import FlowCrypt class KeyStorageMock: KeyStorageType { - func addKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { + func addKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { } - func updateKeys(keyDetails: [KeyDetails], source: KeySource, for email: String) { + func updateKeys(keyDetails: [KeyDetails], passPhrase: String?, source: KeySource, for email: String) { } diff --git a/Podfile.lock b/Podfile.lock index 3ca541b17..ba69805f0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -43,11 +43,11 @@ PODS: - PromisesObjC (2.0.0) - PromisesSwift (2.0.0): - PromisesObjC (= 2.0.0) - - Realm (10.15.1): - - Realm/Headers (= 10.15.1) - - Realm/Headers (10.15.1) - - RealmSwift (10.15.1): - - Realm (= 10.15.1) + - Realm (10.16.0): + - Realm/Headers (= 10.16.0) + - Realm/Headers (10.16.0) + - RealmSwift (10.16.0): + - Realm (= 10.16.0) - SwiftFormat/CLI (0.48.11) - SwiftLint (0.44.0) - SwiftyRSA (1.7.0): @@ -130,8 +130,8 @@ SPEC CHECKSUMS: PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 PromisesSwift: e0b2a6433469efb0b83a2b84c62a2abab8e5e5d4 - Realm: fbcbde2620d51623cc5b18e28f5b165c39abef52 - RealmSwift: e4bea8e42efad3d543aea23b56504069c6faaea2 + Realm: b6027801398f3743fc222f096faa85281b506e6c + RealmSwift: b02a3d0e4947955da960b642c98ad3a461fc4e70 SwiftFormat: 938e5865a118c49d63c7a290ddad86335f9e585f SwiftLint: e96c0a8c770c7ebbc4d36c55baf9096bb65c4584 SwiftyRSA: 8c6dd1ea7db1b8dc4fb517a202f88bb1354bc2c6