import { StateService as StateServiceAbstraction } from "../abstractions/state.service"; import { Account, AccountData } from "../models/domain/account"; import { LogService } from "../abstractions/log.service"; import { StorageService } from "../abstractions/storage.service"; import { HtmlStorageLocation } from "../enums/htmlStorageLocation"; import { KdfType } from "../enums/kdfType"; import { StorageLocation } from "../enums/storageLocation"; import { ThemeType } from "../enums/themeType"; import { UriMatchType } from "../enums/uriMatchType"; import { CipherView } from "../models/view/cipherView"; import { CollectionView } from "../models/view/collectionView"; import { FolderView } from "../models/view/folderView"; import { SendView } from "../models/view/sendView"; import { EncString } from "../models/domain/encString"; import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory"; import { GlobalState } from "../models/domain/globalState"; import { Policy } from "../models/domain/policy"; import { State } from "../models/domain/state"; import { StorageOptions } from "../models/domain/storageOptions"; import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; import { CipherData } from "../models/data/cipherData"; import { CollectionData } from "../models/data/collectionData"; import { EventData } from "../models/data/eventData"; import { FolderData } from "../models/data/folderData"; import { OrganizationData } from "../models/data/organizationData"; import { PolicyData } from "../models/data/policyData"; import { ProviderData } from "../models/data/providerData"; import { SendData } from "../models/data/sendData"; import { BehaviorSubject } from "rxjs"; import { StateMigrationService } from "../abstractions/stateMigration.service"; import { EnvironmentUrls } from "../models/domain/environmentUrls"; import { WindowState } from "../models/domain/windowState"; import { StateFactory } from "../factories/stateFactory"; const keys = { global: "global", authenticatedAccounts: "authenticatedAccounts", activeUserId: "activeUserId", tempAccountSettings: "tempAccountSettings", // used to hold account specific settings (i.e clear clipboard) between initial migration and first account authentication accountActivity: "accountActivity", }; const partialKeys = { autoKey: "_masterkey_auto", biometricKey: "_masterkey_biometric", masterKey: "_masterkey", }; export class StateService< TGlobalState extends GlobalState = GlobalState, TAccount extends Account = Account > implements StateServiceAbstraction { accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({}); activeAccount = new BehaviorSubject(null); protected state: State = new State( this.createGlobals() ); private hasBeenInited: boolean = false; constructor( protected storageService: StorageService, protected secureStorageService: StorageService, protected logService: LogService, protected stateMigrationService: StateMigrationService, protected stateFactory: StateFactory ) {} async init(): Promise { if (this.hasBeenInited) { return; } if (await this.stateMigrationService.needsMigration()) { await this.stateMigrationService.migrate(); } await this.initAccountState(); this.hasBeenInited = true; } async initAccountState() { this.state.authenticatedAccounts = (await this.storageService.get(keys.authenticatedAccounts)) ?? []; for (const i in this.state.authenticatedAccounts) { if (i != null) { await this.syncAccountFromDisk(this.state.authenticatedAccounts[i]); } } const storedActiveUser = await this.storageService.get(keys.activeUserId); if (storedActiveUser != null) { this.state.activeUserId = storedActiveUser; } await this.pushAccounts(); this.activeAccount.next(this.state.activeUserId); } async syncAccountFromDisk(userId: string) { if (userId == null) { return; } this.state.accounts[userId] = this.createAccount(); const diskAccount = await this.getAccountFromDisk({ userId: userId }); this.state.accounts[userId].profile = diskAccount.profile; } async addAccount(account: TAccount) { account = await this.setAccountEnvironmentUrls(account); this.state.authenticatedAccounts.push(account.profile.userId); await this.storageService.save(keys.authenticatedAccounts, this.state.authenticatedAccounts); this.state.accounts[account.profile.userId] = account; await this.scaffoldNewAccountStorage(account); await this.setActiveUser(account.profile.userId); this.activeAccount.next(account.profile.userId); } async setActiveUser(userId: string): Promise { this.clearDecryptedDataForActiveUser(); this.state.activeUserId = userId; await this.storageService.save(keys.activeUserId, userId); this.activeAccount.next(this.state.activeUserId); await this.pushAccounts(); } async clean(options?: StorageOptions): Promise { options = this.reconcileOptions(options, this.defaultInMemoryOptions); await this.deAuthenticateAccount(options.userId); if (options.userId === this.state.activeUserId) { await this.dynamicallySetActiveUser(); } await this.removeAccountFromDisk(options?.userId); this.removeAccountFromMemory(options?.userId); await this.pushAccounts(); } async getAccessToken(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.tokens?.accessToken; } async setAccessToken(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.tokens.accessToken = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getAddEditCipherInfo(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.addEditCipherInfo; } async setAddEditCipherInfo(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.addEditCipherInfo = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getAlwaysShowDock(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.alwaysShowDock ?? false ); } async setAlwaysShowDock(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.alwaysShowDock = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getApiKeyClientId(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.apiKeyClientId; } async setApiKeyClientId(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.apiKeyClientId = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getApiKeyClientSecret(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.apiKeyClientSecret; } async setApiKeyClientSecret(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.apiKeyClientSecret = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getAutoConfirmFingerPrints(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.autoConfirmFingerPrints ?? true ); } async setAutoConfirmFingerprints(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.autoConfirmFingerPrints = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getAutoFillOnPageLoadDefault(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.autoFillOnPageLoadDefault ?? false ); } async setAutoFillOnPageLoadDefault(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.autoFillOnPageLoadDefault = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getBiometricAwaitingAcceptance(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.biometricAwaitingAcceptance ?? false ); } async setBiometricAwaitingAcceptance(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.biometricAwaitingAcceptance = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getBiometricFingerprintValidated(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.biometricFingerprintValidated ?? false ); } async setBiometricFingerprintValidated(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.biometricFingerprintValidated = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getBiometricLocked(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))?.settings ?.biometricLocked ?? false ); } async setBiometricLocked(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.settings.biometricLocked = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getBiometricText(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.biometricText; } async setBiometricText(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.biometricText = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getBiometricUnlock(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.biometricUnlock ?? false ); } async setBiometricUnlock(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.biometricUnlock = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getCanAccessPremium(options?: StorageOptions): Promise { if (!(await this.getIsAuthenticated(options))) { return false; } const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); if (account.profile.hasPremiumPersonally) { return true; } const organizations = await this.getOrganizations(options); if (organizations == null) { return false; } for (const id of Object.keys(organizations)) { const o = organizations[id]; if (o.enabled && o.usersGetPremium && !o.isProviderUser) { return true; } } return false; } async getClearClipboard(options?: StorageOptions): Promise { return ( ( await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ) )?.settings?.clearClipboard ?? null ); } async setClearClipboard(value: number, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.clearClipboard = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getCollapsedGroupings(options?: StorageOptions): Promise> { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.collapsedGroupings; } async setCollapsedGroupings(value: Set, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.collapsedGroupings = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getConvertAccountToKeyConnector(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.convertAccountToKeyConnector; } async setConvertAccountToKeyConnector(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.convertAccountToKeyConnector = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getCryptoMasterKey(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.cryptoMasterKey; } async setCryptoMasterKey(value: SymmetricCryptoKey, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.cryptoMasterKey = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getCryptoMasterKeyAuto(options?: StorageOptions): Promise { options = this.reconcileOptions( this.reconcileOptions(options, { keySuffix: "auto" }), await this.defaultSecureStorageOptions() ); if (options?.userId == null) { return null; } return await this.secureStorageService.get(`${options.userId}${partialKeys.autoKey}`, options); } async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise { options = this.reconcileOptions( this.reconcileOptions(options, { keySuffix: "auto" }), await this.defaultSecureStorageOptions() ); if (options?.userId == null) { return; } await this.secureStorageService.save(`${options.userId}${partialKeys.autoKey}`, value, options); } async getCryptoMasterKeyB64(options?: StorageOptions): Promise { options = this.reconcileOptions(options, await this.defaultSecureStorageOptions()); if (options?.userId == null) { return null; } return await this.secureStorageService.get( `${options?.userId}${partialKeys.masterKey}`, options ); } async setCryptoMasterKeyB64(value: string, options?: StorageOptions): Promise { options = this.reconcileOptions(options, await this.defaultSecureStorageOptions()); if (options?.userId == null) { return; } await this.secureStorageService.save( `${options.userId}${partialKeys.masterKey}`, value, options ); } async getCryptoMasterKeyBiometric(options?: StorageOptions): Promise { options = this.reconcileOptions( this.reconcileOptions(options, { keySuffix: "biometric" }), await this.defaultSecureStorageOptions() ); if (options?.userId == null) { return null; } return await this.secureStorageService.get( `${options.userId}${partialKeys.biometricKey}`, options ); } async hasCryptoMasterKeyBiometric(options?: StorageOptions): Promise { options = this.reconcileOptions( this.reconcileOptions(options, { keySuffix: "biometric" }), await this.defaultSecureStorageOptions() ); if (options?.userId == null) { return false; } return await this.secureStorageService.has( `${options.userId}${partialKeys.biometricKey}`, options ); } async setCryptoMasterKeyBiometric(value: string, options?: StorageOptions): Promise { options = this.reconcileOptions( this.reconcileOptions(options, { keySuffix: "biometric" }), await this.defaultSecureStorageOptions() ); if (options?.userId == null) { return; } await this.secureStorageService.save( `${options.userId}${partialKeys.biometricKey}`, value, options ); } async getDecodedToken(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.tokens?.decodedToken; } async setDecodedToken(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.tokens.decodedToken = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedCiphers(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.ciphers?.decrypted; } async setDecryptedCiphers(value: CipherView[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.ciphers.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedCollections(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.collections?.decrypted; } async setDecryptedCollections(value: CollectionView[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.collections.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedCryptoSymmetricKey(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.cryptoSymmetricKey?.decrypted; } async setDecryptedCryptoSymmetricKey( value: SymmetricCryptoKey, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.cryptoSymmetricKey.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedFolders(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.folders?.decrypted; } async setDecryptedFolders(value: FolderView[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.folders.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedOrganizationKeys( options?: StorageOptions ): Promise> { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.organizationKeys?.decrypted; } async setDecryptedOrganizationKeys( value: Map, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.organizationKeys.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedPasswordGenerationHistory( options?: StorageOptions ): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.passwordGenerationHistory?.decrypted; } async setDecryptedPasswordGenerationHistory( value: GeneratedPasswordHistory[], options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.passwordGenerationHistory.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedPinProtected(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.settings?.pinProtected?.decrypted; } async setDecryptedPinProtected(value: EncString, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.settings.pinProtected.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedPolicies(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.policies?.decrypted; } async setDecryptedPolicies(value: Policy[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.policies.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedPrivateKey(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.privateKey?.decrypted; } async setDecryptedPrivateKey(value: ArrayBuffer, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.privateKey.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedProviderKeys( options?: StorageOptions ): Promise> { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.providerKeys?.decrypted; } async setDecryptedProviderKeys( value: Map, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.providerKeys.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDecryptedSends(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.sends?.decrypted; } async setDecryptedSends(value: SendView[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.sends.decrypted = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getDefaultUriMatch(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.defaultUriMatch; } async setDefaultUriMatch(value: UriMatchType, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.defaultUriMatch = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableAddLoginNotification(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableAddLoginNotification ?? false ); } async setDisableAddLoginNotification(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableAddLoginNotification = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableAutoBiometricsPrompt(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableAutoBiometricsPrompt ?? false ); } async setDisableAutoBiometricsPrompt(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableAutoBiometricsPrompt = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableAutoTotpCopy(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableAutoTotpCopy ?? false ); } async setDisableAutoTotpCopy(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableAutoTotpCopy = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableBadgeCounter(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableBadgeCounter ?? false ); } async setDisableBadgeCounter(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableBadgeCounter = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableChangedPasswordNotification(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableChangedPasswordNotification ?? false ); } async setDisableChangedPasswordNotification( value: boolean, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableChangedPasswordNotification = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableContextMenuItem(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableContextMenuItem ?? false ); } async setDisableContextMenuItem(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableContextMenuItem = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDisableFavicon(options?: StorageOptions): Promise { return ( ( await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ) )?.disableFavicon ?? false ); } async setDisableFavicon(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.disableFavicon = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getDisableGa(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.disableGa ?? false ); } async setDisableGa(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.disableGa = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDontShowCardsCurrentTab(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.dontShowCardsCurrentTab ?? false ); } async setDontShowCardsCurrentTab(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.dontShowCardsCurrentTab = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getDontShowIdentitiesCurrentTab(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.dontShowIdentitiesCurrentTab ?? false ); } async setDontShowIdentitiesCurrentTab(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.dontShowIdentitiesCurrentTab = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEmail(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.profile?.email; } async setEmail(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.profile.email = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getEmailVerified(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.profile.emailVerified ?? false ); } async setEmailVerified(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.emailVerified = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableAlwaysOnTop(options?: StorageOptions): Promise { const accountPreference = ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.enableAlwaysOnTop; const globalPreference = ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.enableAlwaysOnTop; return accountPreference ?? globalPreference ?? false; } async setEnableAlwaysOnTop(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.enableAlwaysOnTop = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableAlwaysOnTop = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableAutoFillOnPageLoad(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.enableAutoFillOnPageLoad ?? false ); } async setEnableAutoFillOnPageLoad(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.enableAutoFillOnPageLoad = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableBiometric(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableBiometrics ?? false ); } async setEnableBiometric(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableBiometrics = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableBrowserIntegration(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableBrowserIntegration ?? false ); } async setEnableBrowserIntegration(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableBrowserIntegration = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableBrowserIntegrationFingerprint(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableBrowserIntegrationFingerprint ?? false ); } async setEnableBrowserIntegrationFingerprint( value: boolean, options?: StorageOptions ): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableBrowserIntegrationFingerprint = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableCloseToTray(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableCloseToTray ?? false ); } async setEnableCloseToTray(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableCloseToTray = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableFullWidth(options?: StorageOptions): Promise { return ( ( await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ) )?.settings?.enableFullWidth ?? false ); } async setEnableFullWidth(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.enableFullWidth = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getEnableGravitars(options?: StorageOptions): Promise { return ( ( await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ) )?.settings?.enableGravitars ?? false ); } async setEnableGravitars(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.enableGravitars = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getEnableMinimizeToTray(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableMinimizeToTray ?? false ); } async setEnableMinimizeToTray(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableMinimizeToTray = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableStartToTray(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableStartToTray ?? false ); } async setEnableStartToTray(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableStartToTray = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEnableTray(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.enableTray ?? false ); } async setEnableTray(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.enableTray = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedCiphers(options?: StorageOptions): Promise<{ [id: string]: CipherData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.data?.ciphers?.encrypted; } async setEncryptedCiphers( value: { [id: string]: CipherData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.data.ciphers.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getEncryptedCollections( options?: StorageOptions ): Promise<{ [id: string]: CollectionData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.data?.collections?.encrypted; } async setEncryptedCollections( value: { [id: string]: CollectionData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.data.collections.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getEncryptedCryptoSymmetricKey(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys.cryptoSymmetricKey.encrypted; } async setEncryptedCryptoSymmetricKey(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.cryptoSymmetricKey.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedFolders(options?: StorageOptions): Promise<{ [id: string]: FolderData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.data?.folders?.encrypted; } async setEncryptedFolders( value: { [id: string]: FolderData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.data.folders.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getEncryptedOrganizationKeys(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.organizationKeys.encrypted; } async setEncryptedOrganizationKeys( value: Map, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.organizationKeys.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedPasswordGenerationHistory( options?: StorageOptions ): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.data?.passwordGenerationHistory?.encrypted; } async setEncryptedPasswordGenerationHistory( value: GeneratedPasswordHistory[], options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.data.passwordGenerationHistory.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedPinProtected(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.pinProtected?.encrypted; } async setEncryptedPinProtected(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.pinProtected.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedPolicies(options?: StorageOptions): Promise<{ [id: string]: PolicyData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.data?.policies?.encrypted; } async setEncryptedPolicies( value: { [id: string]: PolicyData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.data.policies.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedPrivateKey(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.privateKey?.encrypted; } async setEncryptedPrivateKey(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.privateKey.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedProviderKeys(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.providerKeys?.encrypted; } async setEncryptedProviderKeys(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.providerKeys.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEncryptedSends(options?: StorageOptions): Promise<{ [id: string]: SendData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.data?.sends.encrypted; } async setEncryptedSends( value: { [id: string]: SendData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.data.sends.encrypted = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getEntityId(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.profile?.entityId; } async setEntityId(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.profile.entityId = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getEntityType(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.profile?.entityType; } async setEntityType(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.profile.entityType = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getEnvironmentUrls(options?: StorageOptions): Promise { if (this.state.activeUserId == null) { return await this.getGlobalEnvironmentUrls(options); } options = this.reconcileOptions(options, await this.defaultOnDiskOptions()); return (await this.getAccount(options))?.settings?.environmentUrls ?? new EnvironmentUrls(); } async setEnvironmentUrls(value: EnvironmentUrls, options?: StorageOptions): Promise { // Global values are set on each change and the current global settings are passed to any newly authed accounts. // This is to allow setting environement values before an account is active, while still allowing individual accounts to have their own environments. const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.environmentUrls = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEquivalentDomains(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.equivalentDomains; } async setEquivalentDomains(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.equivalentDomains = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEventCollection(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.data?.eventCollection; } async setEventCollection(value: EventData[], options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.data.eventCollection = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getEverBeenUnlocked(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.profile?.everBeenUnlocked ?? false ); } async setEverBeenUnlocked(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.everBeenUnlocked = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getForcePasswordReset(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))?.profile ?.forcePasswordReset ?? false ); } async setForcePasswordReset(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.profile.forcePasswordReset = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getInstalledVersion(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.installedVersion; } async setInstalledVersion(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.installedVersion = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getIsAuthenticated(options?: StorageOptions): Promise { return (await this.getAccessToken(options)) != null && (await this.getUserId(options)) != null; } async getKdfIterations(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.kdfIterations; } async setKdfIterations(value: number, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.kdfIterations = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getKdfType(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.kdfType; } async setKdfType(value: KdfType, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.kdfType = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getKeyHash(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.keyHash; } async setKeyHash(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.keyHash = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getLastActive(options?: StorageOptions): Promise { options = this.reconcileOptions(options, await this.defaultOnDiskOptions()); const accountActivity = await this.storageService.get<{ [userId: string]: number }>( keys.accountActivity, options ); if (accountActivity == null || Object.keys(accountActivity).length < 1) { return null; } return accountActivity[options.userId]; } async setLastActive(value: number, options?: StorageOptions): Promise { options = this.reconcileOptions(options, await this.defaultOnDiskOptions()); if (options.userId == null) { return; } const accountActivity = (await this.storageService.get<{ [userId: string]: number }>( keys.accountActivity, options )) ?? {}; accountActivity[options.userId] = value; await this.storageService.save(keys.accountActivity, accountActivity, options); } async getLastSync(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.profile?.lastSync; } async setLastSync(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.profile.lastSync = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getLegacyEtmKey(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.legacyEtmKey; } async setLegacyEtmKey(value: SymmetricCryptoKey, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.keys.legacyEtmKey = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getLocalData(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.localData; } async setLocalData(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.localData = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getLocale(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.locale; } async setLocale(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.locale = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getLoginRedirect(options?: StorageOptions): Promise { return (await this.getGlobals(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.loginRedirect; } async setLoginRedirect(value: any, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, this.defaultInMemoryOptions) ); globals.loginRedirect = value; await this.saveGlobals(globals, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getMainWindowSize(options?: StorageOptions): Promise { return (await this.getGlobals(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.mainWindowSize; } async setMainWindowSize(value: number, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, this.defaultInMemoryOptions) ); globals.mainWindowSize = value; await this.saveGlobals(globals, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getMinimizeOnCopyToClipboard(options?: StorageOptions): Promise { return ( (await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.settings?.minimizeOnCopyToClipboard ?? false ); } async setMinimizeOnCopyToClipboard(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.minimizeOnCopyToClipboard = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getNeverDomains(options?: StorageOptions): Promise<{ [id: string]: any }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.neverDomains; } async setNeverDomains(value: { [id: string]: any }, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.neverDomains = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getNoAutoPromptBiometrics(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.noAutoPromptBiometrics ?? false ); } async setNoAutoPromptBiometrics(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.noAutoPromptBiometrics = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getNoAutoPromptBiometricsText(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.noAutoPromptBiometricsText; } async setNoAutoPromptBiometricsText(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.noAutoPromptBiometricsText = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getOpenAtLogin(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) ?.openAtLogin ?? false ); } async setOpenAtLogin(value: boolean, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.openAtLogin = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getOrganizationInvitation(options?: StorageOptions): Promise { return (await this.getGlobals(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.organizationInvitation; } async setOrganizationInvitation(value: any, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, this.defaultInMemoryOptions) ); globals.organizationInvitation = value; await this.saveGlobals(globals, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getOrganizations(options?: StorageOptions): Promise<{ [id: string]: OrganizationData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.data?.organizations; } async setOrganizations( value: { [id: string]: OrganizationData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.data.organizations = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getPasswordGenerationOptions(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.passwordGenerationOptions; } async setPasswordGenerationOptions(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.passwordGenerationOptions = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getProtectedPin(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.settings?.protectedPin; } async setProtectedPin(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.settings.protectedPin = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getProviders(options?: StorageOptions): Promise<{ [id: string]: ProviderData }> { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.data?.providers; } async setProviders( value: { [id: string]: ProviderData }, options?: StorageOptions ): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.data.providers = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getPublicKey(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.keys?.publicKey; } async setPublicKey(value: ArrayBuffer, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.keys.publicKey = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getRefreshToken(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.tokens?.refreshToken; } async setRefreshToken(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.tokens.refreshToken = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getRememberedEmail(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.rememberedEmail; } async setRememberedEmail(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.rememberedEmail = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getSecurityStamp(options?: StorageOptions): Promise { return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions))) ?.tokens?.securityStamp; } async setSecurityStamp(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, this.defaultInMemoryOptions) ); account.tokens.securityStamp = value; await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); } async getSettings(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions())) )?.settings?.settings; } async setSettings(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); account.settings.settings = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()) ); } async getSsoCodeVerifier(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.ssoCodeVerifier; } async setSsoCodeVerifier(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.ssoCodeVerifier = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getSsoOrgIdentifier(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.ssoOrganizationIdentifier; } async setSsoOrganizationIdentifier(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.ssoOrganizationIdentifier = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getSsoState(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.ssoState; } async setSsoState(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.ssoState = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getTheme(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.theme; } async setTheme(value: ThemeType, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.theme = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getTwoFactorToken(options?: StorageOptions): Promise { return ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.twoFactorToken; } async setTwoFactorToken(value: string, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); globals.twoFactorToken = value; await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getUserId(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.userId; } async getUsesKeyConnector(options?: StorageOptions): Promise { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.profile?.usesKeyConnector; } async setUsesKeyConnector(value: boolean, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); account.profile.usesKeyConnector = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } async getVaultTimeout(options?: StorageOptions): Promise { const accountVaultTimeout = ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.settings?.vaultTimeout; return accountVaultTimeout; } async setVaultTimeout(value: number, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.vaultTimeout = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getVaultTimeoutAction(options?: StorageOptions): Promise { const accountVaultTimeoutAction = ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.settings?.vaultTimeoutAction; const globalVaultTimeoutAction = ( await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.vaultTimeoutAction; return accountVaultTimeoutAction ?? globalVaultTimeoutAction; } async setVaultTimeoutAction(value: string, options?: StorageOptions): Promise { const account = await this.getAccount( this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.vaultTimeoutAction = value; await this.saveAccount( account, this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getStateVersion(): Promise { return (await this.getGlobals(await this.defaultOnDiskLocalOptions())).stateVersion ?? 1; } async setStateVersion(value: number): Promise { const globals = await this.getGlobals(await this.defaultOnDiskOptions()); globals.stateVersion = value; await this.saveGlobals(globals, await this.defaultOnDiskOptions()); } async getWindow(): Promise { const globals = await this.getGlobals(await this.defaultOnDiskOptions()); return globals?.window != null && Object.keys(globals.window).length > 0 ? globals.window : new WindowState(); } async setWindow(value: WindowState, options?: StorageOptions): Promise { const globals = await this.getGlobals( this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); globals.window = value; return await this.saveGlobals( globals, this.reconcileOptions(options, await this.defaultOnDiskOptions()) ); } protected async getGlobals(options: StorageOptions): Promise { let globals: TGlobalState; if (this.useMemory(options.storageLocation)) { globals = this.getGlobalsFromMemory(); } if (this.useDisk && globals == null) { globals = await this.getGlobalsFromDisk(options); } return globals ?? this.createGlobals(); } protected async saveGlobals(globals: TGlobalState, options: StorageOptions) { return this.useMemory(options.storageLocation) ? this.saveGlobalsToMemory(globals) : await this.saveGlobalsToDisk(globals, options); } protected getGlobalsFromMemory(): TGlobalState { return this.state.globals; } protected async getGlobalsFromDisk(options: StorageOptions): Promise { return await this.storageService.get(keys.global, options); } protected saveGlobalsToMemory(globals: TGlobalState): void { this.state.globals = globals; } protected async saveGlobalsToDisk(globals: TGlobalState, options: StorageOptions): Promise { if (options.useSecureStorage) { await this.secureStorageService.save(keys.global, globals, options); } else { await this.storageService.save(keys.global, globals, options); } } protected async getAccount(options: StorageOptions): Promise { try { let account: TAccount; if (this.useMemory(options.storageLocation)) { account = this.getAccountFromMemory(options); } if (this.useDisk(options.storageLocation) && account == null) { account = await this.getAccountFromDisk(options); } return account; } catch (e) { this.logService.error(e); } } protected getAccountFromMemory(options: StorageOptions): TAccount { if (this.state.accounts == null) { return null; } return this.state.accounts[this.getUserIdFromMemory(options)]; } protected getUserIdFromMemory(options: StorageOptions): string { return options?.userId != null ? this.state.accounts[options.userId]?.profile?.userId : this.state.activeUserId; } protected async getAccountFromDisk(options: StorageOptions): Promise { if (options?.userId == null && this.state.activeUserId == null) { return null; } const account = options?.useSecureStorage ? (await this.secureStorageService.get(options.userId, options)) ?? (await this.storageService.get( options.userId, this.reconcileOptions(options, { htmlStorageLocation: HtmlStorageLocation.Local }) )) : await this.storageService.get(options.userId, options); return account; } protected useMemory(storageLocation: StorageLocation) { return storageLocation === StorageLocation.Memory || storageLocation === StorageLocation.Both; } protected useDisk(storageLocation: StorageLocation) { return storageLocation === StorageLocation.Disk || storageLocation === StorageLocation.Both; } protected async saveAccount( account: TAccount, options: StorageOptions = { storageLocation: StorageLocation.Both, useSecureStorage: false, } ) { return this.useMemory(options.storageLocation) ? await this.saveAccountToMemory(account) : await this.saveAccountToDisk(account, options); } protected async saveAccountToDisk(account: TAccount, options: StorageOptions): Promise { const storageLocation = options.useSecureStorage ? this.secureStorageService : this.storageService; await storageLocation.save(`${options.userId}`, account, options); } protected async saveAccountToMemory(account: TAccount): Promise { if (this.getAccountFromMemory({ userId: account.profile.userId }) !== null) { this.state.accounts[account.profile.userId] = account; } await this.pushAccounts(); } protected async scaffoldNewAccountStorage(account: TAccount): Promise { await this.scaffoldNewAccountLocalStorage(account); await this.scaffoldNewAccountSessionStorage(account); await this.scaffoldNewAccountMemoryStorage(account); } // TODO: There is a tech debt item for splitting up these methods - only Web uses multiple storage locations in its storageService. // For now these methods exist with some redundancy to facilitate this special web requirement. protected async scaffoldNewAccountLocalStorage(account: TAccount): Promise { const storedAccount = await this.storageService.get( account.profile.userId, await this.defaultOnDiskLocalOptions() ); // EnvironmentUrls are set before authenticating and should override whatever is stored from any previous session const environmentUrls = account.settings.environmentUrls; if (storedAccount?.settings != null) { account.settings = storedAccount.settings; } else if (await this.storageService.has(keys.tempAccountSettings)) { account.settings = await this.storageService.get(keys.tempAccountSettings); await this.storageService.remove(keys.tempAccountSettings); } account.settings.environmentUrls = environmentUrls; await this.storageService.save( account.profile.userId, account, await this.defaultOnDiskLocalOptions() ); } protected async scaffoldNewAccountMemoryStorage(account: TAccount): Promise { const storedAccount = await this.storageService.get( account.profile.userId, await this.defaultOnDiskMemoryOptions() ); if (storedAccount?.settings != null) { storedAccount.settings.environmentUrls = account.settings.environmentUrls; account.settings = storedAccount.settings; } await this.storageService.save( account.profile.userId, account, await this.defaultOnDiskMemoryOptions() ); } protected async scaffoldNewAccountSessionStorage(account: TAccount): Promise { const storedAccount = await this.storageService.get( account.profile.userId, await this.defaultOnDiskOptions() ); if (storedAccount?.settings != null) { storedAccount.settings.environmentUrls = account.settings.environmentUrls; account.settings = storedAccount.settings; } await this.storageService.save( account.profile.userId, account, await this.defaultOnDiskOptions() ); } // protected async pushAccounts(): Promise { await this.pruneInMemoryAccounts(); if (this.state?.accounts == null || Object.keys(this.state.accounts).length < 1) { this.accounts.next(null); return; } this.accounts.next(this.state.accounts); } protected reconcileOptions( requestedOptions: StorageOptions, defaultOptions: StorageOptions ): StorageOptions { if (requestedOptions == null) { return defaultOptions; } requestedOptions.userId = requestedOptions?.userId ?? defaultOptions.userId; requestedOptions.storageLocation = requestedOptions?.storageLocation ?? defaultOptions.storageLocation; requestedOptions.useSecureStorage = requestedOptions?.useSecureStorage ?? defaultOptions.useSecureStorage; requestedOptions.htmlStorageLocation = requestedOptions?.htmlStorageLocation ?? defaultOptions.htmlStorageLocation; requestedOptions.keySuffix = requestedOptions?.keySuffix ?? defaultOptions.keySuffix; return requestedOptions; } protected get defaultInMemoryOptions(): StorageOptions { return { storageLocation: StorageLocation.Memory, userId: this.state.activeUserId }; } protected async defaultOnDiskOptions(): Promise { return { storageLocation: StorageLocation.Disk, htmlStorageLocation: HtmlStorageLocation.Session, userId: this.state.activeUserId ?? (await this.getActiveUserIdFromStorage()), useSecureStorage: false, }; } protected async defaultOnDiskLocalOptions(): Promise { return { storageLocation: StorageLocation.Disk, htmlStorageLocation: HtmlStorageLocation.Local, userId: this.state.activeUserId ?? (await this.getActiveUserIdFromStorage()), useSecureStorage: false, }; } protected async defaultOnDiskMemoryOptions(): Promise { return { storageLocation: StorageLocation.Disk, htmlStorageLocation: HtmlStorageLocation.Memory, userId: this.state.activeUserId ?? (await this.getUserId()), useSecureStorage: false, }; } protected async defaultSecureStorageOptions(): Promise { return { storageLocation: StorageLocation.Disk, useSecureStorage: true, userId: this.state.activeUserId ?? (await this.getActiveUserIdFromStorage()), }; } protected async getActiveUserIdFromStorage(): Promise { return await this.storageService.get(keys.activeUserId); } protected async removeAccountFromLocalStorage( userId: string = this.state.activeUserId ): Promise { const storedAccount = await this.storageService.get(userId, { htmlStorageLocation: HtmlStorageLocation.Local, }); await this.storageService.save( userId, this.resetAccount(storedAccount), await this.defaultOnDiskLocalOptions() ); } protected async removeAccountFromSessionStorage( userId: string = this.state.activeUserId ): Promise { const storedAccount = await this.storageService.get(userId, { htmlStorageLocation: HtmlStorageLocation.Session, }); await this.storageService.save( userId, this.resetAccount(storedAccount), await this.defaultOnDiskOptions() ); } protected async removeAccountFromSecureStorage( userId: string = this.state.activeUserId ): Promise { await this.setCryptoMasterKeyAuto(null, { userId: userId }); await this.setCryptoMasterKeyBiometric(null, { userId: userId }); await this.setCryptoMasterKeyB64(null, { userId: userId }); } protected removeAccountFromMemory(userId: string = this.state.activeUserId): void { delete this.state.accounts[userId]; } protected async pruneInMemoryAccounts() { // We preserve settings for logged out accounts, but we don't want to consider them when thinking about active account state for (const userId in this.state.accounts) { if (!(await this.getIsAuthenticated({ userId: userId }))) { delete this.state.accounts[userId]; } } } // settings persist even on reset, and are not effected by this method protected resetAccount(account: TAccount) { const persistentAccountInformation = { settings: account.settings }; return Object.assign(this.createAccount(), persistentAccountInformation); } protected async setAccountEnvironmentUrls(account: TAccount): Promise { account.settings.environmentUrls = await this.getGlobalEnvironmentUrls(); return account; } protected async getGlobalEnvironmentUrls(options?: StorageOptions): Promise { options = this.reconcileOptions(options, await this.defaultOnDiskOptions()); return (await this.getGlobals(options)).environmentUrls ?? new EnvironmentUrls(); } protected clearDecryptedDataForActiveUser() { const userId = this.state.activeUserId; if (userId == null) { return; } this.state.accounts[userId].data = new AccountData(); } protected createAccount(init: Partial = null): TAccount { return this.stateFactory.createAccount(init); } protected createGlobals(init: Partial = null): TGlobalState { return this.stateFactory.createGlobal(init); } protected async deAuthenticateAccount(userId: string) { await this.setAccessToken(null, { userId: userId }); const index = this.state.authenticatedAccounts.indexOf(userId); if (index > -1) { this.state.authenticatedAccounts.splice(index, 1); await this.storageService.save(keys.authenticatedAccounts, this.state.authenticatedAccounts); } } protected async removeAccountFromDisk(userId: string) { await this.removeAccountFromSessionStorage(userId); await this.removeAccountFromLocalStorage(userId); await this.removeAccountFromSecureStorage(userId); } protected async dynamicallySetActiveUser() { for (const userId in this.state.accounts) { if (userId == null) { continue; } if (await this.getIsAuthenticated({ userId: userId })) { await this.setActiveUser(userId); break; } await this.setActiveUser(null); } } }