Skip to content

Commit

Permalink
Improve account loading flow in remote service
Browse files Browse the repository at this point in the history
- Fix last selected account not restoring on app reopen #19
  • Loading branch information
jlcvp committed Oct 10, 2024
1 parent 42e7673 commit 4199c2d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 24 deletions.
59 changes: 38 additions & 21 deletions src/app/home/home.page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, HostListener, OnInit, ViewChild } from '@angular/core';
import { AuthenticationService } from '../services/authentication.service';
import { AlertController, IonModal, LoadingController, ModalController, NavController, ToastController } from '@ionic/angular';
import { firstValueFrom, Observable } from 'rxjs';
import { firstValueFrom, Observable, tap } from 'rxjs';
import { Account2FA } from '../models/account2FA.model';
import { Account2faService } from '../services/accounts/account2fa.service';
import { LogoService } from '../services/logo.service';
Expand Down Expand Up @@ -54,7 +54,6 @@ export class HomePage implements OnInit {

accounts$: Observable<Account2FA[]> = new Observable<Account2FA[]>();
selectedAccount?: Account2FA
lockedAccount?: Account2FA
searchTxt: string = ''
draftLogoSearchTxt: string = ''
searchLogoResults: any[] = []
Expand All @@ -67,12 +66,13 @@ export class HomePage implements OnInit {
isScanActive: boolean = false
isWindowFocused: boolean = true
hasLockedAccounts: boolean = false
versionInfo
versionInfo: any

private encryptionOptions: EncryptionOptions = ENCRYPTION_OPTIONS_DEFAULT
private systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)');
private isLandscape: boolean = false
private currentDarkModePref: string = '';
private shouldAlertAboutLockedAccounts: boolean = true
constructor(
private authService: AuthenticationService,
private accountsService: Account2faService,
Expand Down Expand Up @@ -662,25 +662,19 @@ export class HomePage implements OnInit {
backdropDismiss: false
})
await loading.present()
const accounts$ = await this.accountsService.getAccounts()

// detect if there are locked accounts and call activate encryption flow
const accounts = await firstValueFrom(accounts$)
const lockedAccount = accounts.find(account => account.isLocked)
await loading.dismiss()
if(lockedAccount) {
this.hasLockedAccounts = true
if(await this.alertAccountsLocked()) { // user wants to informPassword
const password = await this.promptUnlockPassword(lockedAccount)
if(password) { // user provided the correct password
// save password and enable encryption
await this.configService.setEncryptionKey(password)
await this.configService.setLastPasswordCheck()
await this.setEncryptionActive(true)
this.hasLockedAccounts = false
}
const accounts$ = (await this.accountsService.getAccounts()).pipe(tap(accounts => {
const lockedAccount = accounts.find(account => account.isLocked)
this.hasLockedAccounts = !!lockedAccount
if(this.shouldAlertAboutLockedAccounts && lockedAccount) {
this.shouldAlertAboutLockedAccounts = false
this.handleAccountsLocked(lockedAccount)
}
}
this.handleAccountSelection(accounts)
console.log("Accounts tapped", { accounts })
}))

await loading.dismiss()

this.accounts$ = accounts$
}
Expand Down Expand Up @@ -869,7 +863,7 @@ export class HomePage implements OnInit {

private async handleEncryptionReminder() {
const isFirstLaunch = await this.configService.isFirstRun()
if (this.shouldAlertToActivateEncryption && !isFirstLaunch) { // 2.1
if (this.shouldAlertToActivateEncryption && !isFirstLaunch && this.shouldAlertAboutLockedAccounts) { // 2.1
const shouldEnableEncryption = await this.alertToActivateEncryption()
if(shouldEnableEncryption) { // 2.1.1
await this.activateEncryption()
Expand Down Expand Up @@ -1041,6 +1035,29 @@ export class HomePage implements OnInit {
return ''
}

private async handleAccountsLocked(lockedAccount: Account2FA): Promise<void> {
if(await this.alertAccountsLocked()) { // user wants to informPassword
const password = await this.promptUnlockPassword(lockedAccount)
if(password) { // user provided the correct password
// save password and enable encryption
await this.configService.setEncryptionKey(password)
await this.configService.setLastPasswordCheck()
await this.setEncryptionActive(true)
this.hasLockedAccounts = false
}
}
}

private async handleAccountSelection(accounts: Account2FA[]): Promise<void> {
const lastSelectedAccountId = await this.storageService.get<string>('lastSelectedAccountId')
if (lastSelectedAccountId) {
const selectedAccount = accounts.find(account => account.id === lastSelectedAccountId)
if (selectedAccount) {
this.selectAccount(selectedAccount)
}
}
}

private async alertAccountsLocked(): Promise<boolean> {
const title = await firstValueFrom(this.translateService.get('HOME.ERRORS.ACCOUNTS_LOCKED_TITLE'))
const message = await firstValueFrom(this.translateService.get('HOME.ERRORS.ACCOUNTS_LOCKED'))
Expand Down
6 changes: 3 additions & 3 deletions src/app/services/accounts/remote-account2fa.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { inject, Injectable } from '@angular/core';
import { Account2FA, IAccount2FA, IAccount2FAProvider } from '../../models/account2FA.model';
import { BehaviorSubject, debounceTime, firstValueFrom, map, Observable, throttleTime } from 'rxjs';
import { BehaviorSubject, map, Observable, throttleTime } from 'rxjs';
import { AuthenticationService } from '../authentication.service';
import { clearIndexedDbPersistence, collection, collectionData, doc, Firestore, orderBy, query, runTransaction, serverTimestamp, setDoc, terminate, Timestamp, where, writeBatch } from '@angular/fire/firestore';
import { LocalAccount2faService } from './local-account2fa.service';
Expand All @@ -17,7 +17,7 @@ export class RemoteAccount2faService implements IAccount2FAProvider {
private accounts$: Observable<Account2FA[]>

constructor(private authService: AuthenticationService, private localAccountService: LocalAccount2faService) {
this.accounts$ = this.accountsSubject.asObservable().pipe(throttleTime(1000))
this.accounts$ = this.accountsSubject.asObservable()
}

async getAccounts(): Promise<Observable<Account2FA[]>> {
Expand Down Expand Up @@ -92,7 +92,7 @@ export class RemoteAccount2faService implements IAccount2FAProvider {
console.error('Failed to load remote accounts', {error})
}
// delay a little bit more before resolving to let the local service settle the first value
await new Promise((resolve, _) => { setTimeout(resolve, 500)});
// await new Promise((resolve, _) => { setTimeout(resolve, 500)});
console.log("Loaded accounts")
this.loaded = true
}
Expand Down

0 comments on commit 4199c2d

Please sign in to comment.