From 58de36ee5ea646686bc424271e7ca108c9d26e6a Mon Sep 17 00:00:00 2001 From: Anton Kharchevskyi Date: Thu, 17 Jun 2021 00:21:44 +0300 Subject: [PATCH 1/3] Cleanup user session on app start --- .../SideMenu/Menu/MyMenuViewController.swift | 2 +- FlowCrypt/Core/Core.swift | 6 +++++- .../DataManager/DataService.swift | 19 ++++++++++--------- .../Encrypted Storage/EncryptedStorage.swift | 12 ++++++++++++ .../DataManager/UserAccountService.swift | 18 ++++++++++++++++++ .../Functionality/Services/AppStartup.swift | 10 +++++++--- .../Functionality/Services/GlobalRouter.swift | 1 + FlowCrypt/Models/OrganisationalRule.swift | 4 ++-- FlowCryptTests/FlowCryptCoreTests.swift | 4 +++- 9 files changed, 59 insertions(+), 17 deletions(-) diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index ed6cfe440..8765151ed 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -43,7 +43,7 @@ final class MyMenuViewController: ASDKViewController { private var folders: [FolderViewModel] = [] private let serviceItems: [FolderViewModel] = FolderViewModel.menuItems - private var accounts: [User] { dataService.users.filter { !$0.isActive } } + private var accounts: [User] { dataService.validAccounts() } private let tableNode: ASTableNode diff --git a/FlowCrypt/Core/Core.swift b/FlowCrypt/Core/Core.swift index ce8d7c1ad..28f1dc5c1 100644 --- a/FlowCrypt/Core/Core.swift +++ b/FlowCrypt/Core/Core.swift @@ -101,7 +101,10 @@ final class Core { return try r.json.decodeJson(as: CoreRes.ZxcvbnStrengthBar.self) } - public func startInBackgroundIfNotAlreadyRunning() { + public func startInBackgroundIfNotAlreadyRunning(_ completion: @escaping (() -> Void)) { + if self.ready { + completion() + } if !started { started = true DispatchQueue.global(qos: .default).async { [weak self] in @@ -123,6 +126,7 @@ final class Core { self.context!.setObject(unsafeBitCast(cb_last_value_filler, to: AnyObject.self), forKeyedSubscript: "engine_host_cb_catcher" as (NSCopying & NSObjectProtocol)?) self.ready = true self.logger.logInfo("JsContext took \(trace.finish()) to start") + completion() } } } diff --git a/FlowCrypt/Functionality/DataManager/DataService.swift b/FlowCrypt/Functionality/DataManager/DataService.swift index e162227df..eeee7c8f4 100644 --- a/FlowCrypt/Functionality/DataManager/DataService.swift +++ b/FlowCrypt/Functionality/DataManager/DataService.swift @@ -20,6 +20,8 @@ protocol DataServiceType { var token: String? { get } var users: [User] { get } + + func validAccounts() -> [User] } protocol ImapSessionProvider { @@ -64,15 +66,7 @@ extension DataService: DataServiceType { guard let currentUser = currentUser else { return false } - guard let keys = encryptedStorage.keys() else { - return false - } - let isAnyKeysForCurrentUser = keys - .map(\.account) - .map { $0.contains(currentUser.email) } - .contains(true) - - return isAnyKeysForCurrentUser + return encryptedStorage.isAnyKey(for: currentUser.email) } var isLoggedIn: Bool { @@ -109,6 +103,13 @@ extension DataService: DataServiceType { return nil } } + + func validAccounts() -> [User] { + encryptedStorage.getAllUsers() + .filter { encryptedStorage.isAnyKey(for: $0.email) } + .filter { $0.email != currentUser?.email } + .map(User.init) + } } // MARK: - DataKeyServiceType diff --git a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift index 2941ef728..d899af0f6 100644 --- a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift +++ b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift @@ -22,6 +22,7 @@ protocol EncryptedStorageType { func getAllUsers() -> [UserObject] func saveActiveUser(with user: UserObject) var activeUser: UserObject? { get } + func isAnyKey(for email: String) -> Bool func cleanup() } @@ -189,6 +190,16 @@ extension EncryptedStorage { .map(\.public) .first } + + func isAnyKey(for email: String) -> Bool { + guard let keys = keys() else { + return false + } + return keys + .map(\.account) + .map { $0.contains(email) } + .contains(true) + } } // MARK: - User @@ -207,6 +218,7 @@ extension EncryptedStorage { self.getAllUsers().forEach { $0.isActive = false } + user.isActive = true self.storage.add(user, update: .all) } } diff --git a/FlowCrypt/Functionality/DataManager/UserAccountService.swift b/FlowCrypt/Functionality/DataManager/UserAccountService.swift index 66d06a87e..6a3ef9c71 100644 --- a/FlowCrypt/Functionality/DataManager/UserAccountService.swift +++ b/FlowCrypt/Functionality/DataManager/UserAccountService.swift @@ -13,6 +13,7 @@ protocol UserAccountServiceType { func startSessionFor(user type: SessionType) func switchActiveSessionFor(user: User) -> SessionType? func startActiveSessionForNextUser() -> SessionType? + func cleanupSessions() func cleanup() } @@ -95,6 +96,20 @@ extension UserAccountService: UserAccountServiceType { return session } + func cleanupSessions() { + encryptedStorage.getAllUsers() + .filter { !encryptedStorage.isAnyKey(for: $0.email) } + .map(\.email) + .forEach(logOut) + + let users = encryptedStorage.getAllUsers() + + if !users.contains(where: { $0.isActive }), let user = users.first(where: { encryptedStorage.isAnyKey(for: $0.email ) }) { + switchActiveSession(for: user) + } + } + + @discardableResult private func switchActiveSession(for userObject: UserObject) -> SessionType? { let sessionType: SessionType switch userObject.authType { @@ -117,7 +132,10 @@ extension UserAccountService: UserAccountServiceType { logger.logWarning("User is not logged in. Can't log out") return } + logOut(user: email) + } + private func logOut(user email: String) { switch dataService.currentAuthType { case .oAuthGmail: googleService.signOut(user: email) diff --git a/FlowCrypt/Functionality/Services/AppStartup.swift b/FlowCrypt/Functionality/Services/AppStartup.swift index cee8e4ce2..20f8e4731 100644 --- a/FlowCrypt/Functionality/Services/AppStartup.swift +++ b/FlowCrypt/Functionality/Services/AppStartup.swift @@ -19,7 +19,7 @@ struct AppStartup { window.rootViewController = BootstrapViewController() window.makeKeyAndVisible() Promise { - self.setupCore() + try awaitPromise(self.setupCore()) try self.setupMigrationIfNeeded() try self.setupSession() }.then(on: .main) { @@ -29,8 +29,12 @@ struct AppStartup { } } - private func setupCore() { - Core.shared.startInBackgroundIfNotAlreadyRunning() + private func setupCore() -> Promise { + Promise { resolve, _ in + Core.shared.startInBackgroundIfNotAlreadyRunning { + resolve(()) + } + } } private func setupMigrationIfNeeded() throws { diff --git a/FlowCrypt/Functionality/Services/GlobalRouter.swift b/FlowCrypt/Functionality/Services/GlobalRouter.swift index 55d8ff3d5..c0d2d3709 100644 --- a/FlowCrypt/Functionality/Services/GlobalRouter.swift +++ b/FlowCrypt/Functionality/Services/GlobalRouter.swift @@ -55,6 +55,7 @@ final class GlobalRouter: GlobalRouterType { extension GlobalRouter { /// proceed to flow (signing/setup/app) depends on user status (isLoggedIn/isSetupFinished) func proceed() { + userAccountService.cleanupSessions() proceed(with: nil) } diff --git a/FlowCrypt/Models/OrganisationalRule.swift b/FlowCrypt/Models/OrganisationalRule.swift index 7321bd8ea..7c009be16 100644 --- a/FlowCrypt/Models/OrganisationalRule.swift +++ b/FlowCrypt/Models/OrganisationalRule.swift @@ -43,12 +43,12 @@ class OrganisationalRules { self.domainRules = domainRules self.domain = domain } - + init?(domainRules: DomainRules, email: String) { guard let recipientDomain = email.recipientDomain else { return nil } - + self.domain = recipientDomain self.domainRules = domainRules } diff --git a/FlowCryptTests/FlowCryptCoreTests.swift b/FlowCryptTests/FlowCryptCoreTests.swift index 8478d4c3f..d2524b4cb 100644 --- a/FlowCryptTests/FlowCryptCoreTests.swift +++ b/FlowCryptTests/FlowCryptCoreTests.swift @@ -15,7 +15,9 @@ class FlowCryptCoreTests: XCTestCase { super.setUp() // DispatchQueue.promises = .global() // this helps prevent Promise deadlocks - but currently Promises are not in use by tests core = Core.shared - core.startInBackgroundIfNotAlreadyRunning() + core.startInBackgroundIfNotAlreadyRunning { + + } do { try core.blockUntilReadyOrThrow() } catch { From c14ad6d8271cc179e2e71bda3fe1ba51afced8a2 Mon Sep 17 00:00:00 2001 From: Anton Kharchevskyi Date: Thu, 17 Jun 2021 11:39:05 +0300 Subject: [PATCH 2/3] Force reload folders on account switch --- .../Inbox/Container/InboxViewControllerContainer.swift | 2 +- .../Controllers/SideMenu/Menu/MyMenuViewController.swift | 2 +- .../Services/Folders Services/FoldersService.swift | 8 ++++++-- .../Services/Folders Services/TrashFolderProvider.swift | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift index 223d0b114..52941eaad 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift @@ -56,7 +56,7 @@ final class InboxViewControllerContainer: TableNodeViewController { } private func fetchInboxFolder() { - folderService.fetchFolders() + folderService.fetchFolders(isForceReload: true) .then(on: .main) { [weak self] folders in self?.handleFetched(folders: folders) } diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index 8765151ed..40e7d23fb 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -161,7 +161,7 @@ extension MyMenuViewController: ASTableDataSource, ASTableDelegate { extension MyMenuViewController { private func fetchFolders() { showSpinner() - foldersProvider.fetchFolders() + foldersProvider.fetchFolders(isForceReload: false) .then(on: .main) { [weak self] folders in self?.handleNewFolders(with: folders) } diff --git a/FlowCrypt/Functionality/Services/Folders Services/FoldersService.swift b/FlowCrypt/Functionality/Services/Folders Services/FoldersService.swift index d58c32b5a..57f5e3ce4 100644 --- a/FlowCrypt/Functionality/Services/Folders Services/FoldersService.swift +++ b/FlowCrypt/Functionality/Services/Folders Services/FoldersService.swift @@ -14,7 +14,7 @@ protocol TrashFolderProviderType { } protocol FoldersServiceType { - func fetchFolders() -> Promise<[FolderViewModel]> + func fetchFolders(isForceReload: Bool) -> Promise<[FolderViewModel]> } final class FoldersService: FoldersServiceType { @@ -34,7 +34,11 @@ final class FoldersService: FoldersServiceType { self.localStorage = localStorage } - func fetchFolders() -> Promise<[FolderViewModel]> { + func fetchFolders(isForceReload: Bool) -> Promise<[FolderViewModel]> { + if isForceReload { + return getAndSaveFolders() + } + let localFolders = self.localFoldersProvider.fetchFolders() if localFolders.isEmpty { diff --git a/FlowCrypt/Functionality/Services/Folders Services/TrashFolderProvider.swift b/FlowCrypt/Functionality/Services/Folders Services/TrashFolderProvider.swift index 4dd6b1ad2..8937e127d 100644 --- a/FlowCrypt/Functionality/Services/Folders Services/TrashFolderProvider.swift +++ b/FlowCrypt/Functionality/Services/Folders Services/TrashFolderProvider.swift @@ -28,7 +28,7 @@ extension TrashFolderProvider: TrashFolderProviderType { } else { return Promise { resolve, _ in // will get all folders - _ = try awaitPromise(folderProvider.fetchFolders()) + _ = try awaitPromise(folderProvider.fetchFolders(isForceReload: true)) resolve(localStorage.trashFolderPath) } } From 70228465bb098aacd260e0338b4681360c54a41b Mon Sep 17 00:00:00 2001 From: Anton Kharchevskyi Date: Sat, 19 Jun 2021 18:19:50 +0300 Subject: [PATCH 3/3] Merge origin --- .../DataManager/Encrypted Storage/EncryptedStorage.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift index bce1c1d28..82905a208 100644 --- a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift +++ b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift @@ -183,10 +183,7 @@ extension EncryptedStorage { } func isAnyKey(for email: String) -> Bool { - guard let keys = keys() else { - return false - } - return keys + keysInfo() .map(\.account) .map { $0.contains(email) } .contains(true)