diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewControllerContainer.swift index cf1ba02fa..1750f2492 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 31413ddde..94230ced4 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 var serviceItems: [FolderViewModel] { FolderViewModel.menuItems } - private var accounts: [User] { dataService.users.filter { !$0.isActive } } + private var accounts: [User] { dataService.validAccounts() } private let tableNode: ASTableNode @@ -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/Core/Core.swift b/FlowCrypt/Core/Core.swift index b2115515e..dcc87cf1b 100644 --- a/FlowCrypt/Core/Core.swift +++ b/FlowCrypt/Core/Core.swift @@ -105,7 +105,10 @@ final class Core: KeyDecrypter { return try r.json.decodeJson(as: CoreRes.ZxcvbnStrengthBar.self) } - public func startInBackgroundIfNotAlreadyRunning(_ completion: (() -> Void)? = nil) { + public func startInBackgroundIfNotAlreadyRunning(_ completion: @escaping (() -> Void)) { + if self.ready { + completion() + } if !started { started = true DispatchQueue.global(qos: .default).async { [weak self] in @@ -127,7 +130,7 @@ final class Core: KeyDecrypter { 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?() + completion() } } } diff --git a/FlowCrypt/Functionality/DataManager/DataService.swift b/FlowCrypt/Functionality/DataManager/DataService.swift index 40da8f7f5..ade0e370a 100644 --- a/FlowCrypt/Functionality/DataManager/DataService.swift +++ b/FlowCrypt/Functionality/DataManager/DataService.swift @@ -20,6 +20,8 @@ protocol DataServiceType: EmailProviderType { var token: String? { get } var users: [User] { get } + + func validAccounts() -> [User] } protocol ImapSessionProvider { @@ -73,13 +75,7 @@ extension DataService: DataServiceType { guard let currentUser = currentUser else { return false } - - let isAnyKeysForCurrentUser = encryptedStorage.keysInfo() - .map(\.account) - .map { $0.contains(currentUser.email) } - .contains(true) - - return isAnyKeysForCurrentUser + return encryptedStorage.isAnyKey(for: currentUser.email) } var isLoggedIn: Bool { @@ -116,6 +112,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: - Migration diff --git a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift index 1079ced62..82905a208 100644 --- a/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift +++ b/FlowCrypt/Functionality/DataManager/Encrypted Storage/EncryptedStorage.swift @@ -17,6 +17,7 @@ protocol EncryptedStorageType: KeyStorageType { func getAllUsers() -> [UserObject] func saveActiveUser(with user: UserObject) var activeUser: UserObject? { get } + func isAnyKey(for email: String) -> Bool func cleanup() } @@ -180,6 +181,13 @@ extension EncryptedStorage { .map(\.public) .first } + + func isAnyKey(for email: String) -> Bool { + keysInfo() + .map(\.account) + .map { $0.contains(email) } + .contains(true) + } } // MARK: - PassPhrase @@ -223,6 +231,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 8e318ac65..a433a3ba3 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/Folders Services/FoldersService.swift b/FlowCrypt/Functionality/Services/Folders Services/FoldersService.swift index e5f93adeb..764b36179 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) } } 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) }