diff --git a/common/src/models/domain/globalState.ts b/common/src/models/domain/globalState.ts index f14d48d3e5..7a1895d1ff 100644 --- a/common/src/models/domain/globalState.ts +++ b/common/src/models/domain/globalState.ts @@ -25,6 +25,6 @@ export class GlobalState { biometricText?: string; noAutoPromptBiometrics?: boolean; noAutoPromptBiometricsText?: string; - stateVersion: StateVersion = StateVersion.Latest; + stateVersion: StateVersion = StateVersion.One; environmentUrls: EnvironmentUrls = new EnvironmentUrls(); } diff --git a/common/src/services/state.service.ts b/common/src/services/state.service.ts index 68cbe7890e..60975d5721 100644 --- a/common/src/services/state.service.ts +++ b/common/src/services/state.service.ts @@ -41,6 +41,7 @@ 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 }; const partialKeys = { @@ -2213,6 +2214,9 @@ export class StateService // EnvironmentUrls are set before authenticating and should override whatever is stored from last session storedAccount.settings.environmentUrls = account.settings.environmentUrls; 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); } await this.storageService.save( account.profile.userId, diff --git a/common/src/services/stateMigration.service.ts b/common/src/services/stateMigration.service.ts index 59db60722e..36bf686486 100644 --- a/common/src/services/stateMigration.service.ts +++ b/common/src/services/stateMigration.service.ts @@ -1,9 +1,7 @@ import { StorageService } from "../abstractions/storage.service"; -import { Account } from "../models/domain/account"; import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory"; import { GlobalState } from "../models/domain/globalState"; -import { State } from "../models/domain/state"; import { StorageOptions } from "../models/domain/storageOptions"; import { CipherData } from "../models/data/cipherData"; @@ -18,11 +16,12 @@ import { SendData } from "../models/data/sendData"; import { HtmlStorageLocation } from "../enums/htmlStorageLocation"; import { KdfType } from "../enums/kdfType"; import { StateVersion } from "../enums/stateVersion"; + import { EnvironmentUrls } from "../models/domain/environmentUrls"; // Originally (before January 2022) storage was handled as a flat key/value pair store. // With the move to a typed object for state storage these keys should no longer be in use anywhere outside of this migration. -const v1Keys = { +const v1Keys: { [key: string]: string } = { accessToken: "accessToken", alwaysShowDock: "alwaysShowDock", autoConfirmFingerprints: "autoConfirmFingerprints", @@ -100,7 +99,7 @@ const v1Keys = { rememberedEmail: "rememberedEmail", }; -const v1KeyPrefixes = { +const v1KeyPrefixes: { [key: string]: string } = { ciphers: "ciphers_", collections: "collections_", folders: "folders_", @@ -117,6 +116,7 @@ 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 }; const partialKeys = { @@ -132,17 +132,12 @@ export class StateMigrationService { ) {} async needsMigration(): Promise { - const currentStateVersion = ( - await this.storageService.get(keys.global, { - htmlStorageLocation: HtmlStorageLocation.Local, - }) - )?.stateVersion; + const currentStateVersion = await this.getCurrentStateVersion(); return currentStateVersion == null || currentStateVersion < StateVersion.Latest; } async migrate(): Promise { - let currentStateVersion = - (await this.storageService.get(keys.global))?.stateVersion ?? StateVersion.One; + let currentStateVersion = await this.getCurrentStateVersion(); while (currentStateVersion < StateVersion.Latest) { switch (currentStateVersion) { case StateVersion.One: @@ -155,362 +150,244 @@ export class StateMigrationService { } protected async migrateStateFrom1To2(): Promise { - const options: StorageOptions = { htmlStorageLocation: HtmlStorageLocation.Local }; - const userId = await this.storageService.get("userId"); - const initialState: State = - userId == null - ? { - globals: new GlobalState(), - accounts: {}, - activeUserId: null, - authenticatedAccounts: [], + const clearV1Keys = async (clearingUserId?: string) => { + for (const key in v1Keys) { + if (key == null) { + continue; + } + await this.set(v1Keys[key], null); + } + if (clearingUserId != null) { + for (const keyPrefix in v1KeyPrefixes) { + if (keyPrefix == null) { + continue; } - : { - authenticatedAccounts: [userId], - activeUserId: userId, - globals: { - biometricAwaitingAcceptance: await this.storageService.get( - v1Keys.biometricAwaitingAcceptance, - options - ), - biometricFingerprintValidated: await this.storageService.get( - v1Keys.biometricFingerprintValidated, - options - ), - biometricText: await this.storageService.get(v1Keys.biometricText, options), - disableFavicon: await this.storageService.get( - v1Keys.disableFavicon, - options - ), - enableAlwaysOnTop: await this.storageService.get( - v1Keys.enableAlwaysOnTop, - options - ), - enableBiometrics: await this.storageService.get( - v1Keys.enableBiometric, - options - ), - environmentUrls: null, - installedVersion: await this.storageService.get( - v1Keys.installedVersion, - options - ), - locale: await this.storageService.get(v1Keys.locale, options), - loginRedirect: null, - mainWindowSize: null, - noAutoPromptBiometrics: await this.storageService.get( - v1Keys.disableAutoBiometricsPrompt, - options - ), - noAutoPromptBiometricsText: await this.storageService.get( - v1Keys.noAutoPromptBiometricsText, - options - ), - openAtLogin: await this.storageService.get(v1Keys.openAtLogin, options), - organizationInvitation: await this.storageService.get("", options), - ssoCodeVerifier: await this.storageService.get( - v1Keys.ssoCodeVerifier, - options - ), - ssoOrganizationIdentifier: await this.storageService.get( - v1Keys.ssoIdentifier, - options - ), - ssoState: null, - rememberedEmail: await this.storageService.get( - v1Keys.rememberedEmail, - options - ), - stateVersion: StateVersion.Two, - theme: await this.storageService.get(v1Keys.theme, options), - twoFactorToken: await this.storageService.get( - v1KeyPrefixes.twoFactorToken + userId, - options - ), - vaultTimeout: await this.storageService.get(v1Keys.vaultTimeout, options), - vaultTimeoutAction: await this.storageService.get( - v1Keys.vaultTimeoutAction, - options - ), - window: null, - }, - accounts: { - [userId]: new Account({ - data: { - addEditCipherInfo: null, - ciphers: { - decrypted: null, - encrypted: await this.storageService.get<{ [id: string]: CipherData }>( - v1KeyPrefixes.ciphers + userId, - options - ), - }, - collapsedGroupings: null, - collections: { - decrypted: null, - encrypted: await this.storageService.get<{ [id: string]: CollectionData }>( - v1KeyPrefixes.collections + userId, - options - ), - }, - eventCollection: await this.storageService.get( - v1Keys.eventCollection, - options - ), - folders: { - decrypted: null, - encrypted: await this.storageService.get<{ [id: string]: FolderData }>( - v1KeyPrefixes.folders + userId, - options - ), - }, - localData: null, - organizations: await this.storageService.get<{ [id: string]: OrganizationData }>( - v1KeyPrefixes.organizations + userId - ), - passwordGenerationHistory: { - decrypted: null, - encrypted: await this.storageService.get( - "TODO", - options - ), // TODO: Whats up here? - }, - policies: { - decrypted: null, - encrypted: await this.storageService.get<{ [id: string]: PolicyData }>( - v1KeyPrefixes.policies + userId, - options - ), - }, - providers: await this.storageService.get<{ [id: string]: ProviderData }>( - v1KeyPrefixes.providers + userId - ), - sends: { - decrypted: null, - encrypted: await this.storageService.get<{ [id: string]: SendData }>( - v1KeyPrefixes.sends, - options - ), - }, - }, - keys: { - apiKeyClientSecret: await this.storageService.get( - v1Keys.clientSecret, - options - ), - cryptoMasterKey: null, - cryptoMasterKeyAuto: null, - cryptoMasterKeyB64: null, - cryptoMasterKeyBiometric: null, - cryptoSymmetricKey: { - encrypted: await this.storageService.get(v1Keys.encKey, options), - decrypted: null, - }, - legacyEtmKey: null, - organizationKeys: { - decrypted: null, - encrypted: await this.storageService.get( - v1Keys.encOrgKeys + userId, - options - ), - }, - privateKey: { - decrypted: null, - encrypted: await this.storageService.get(v1Keys.encPrivate, options), - }, - providerKeys: { - decrypted: null, - encrypted: await this.storageService.get( - v1Keys.encProviderKeys + userId, - options - ), - }, - publicKey: null, - }, - profile: { - apiKeyClientId: await this.storageService.get(v1Keys.clientId, options), - authenticationStatus: null, - convertAccountToKeyConnector: await this.storageService.get( - v1Keys.convertAccountToKeyConnector, - options - ), - email: await this.storageService.get(v1Keys.userEmail, options), - emailVerified: await this.storageService.get( - v1Keys.emailVerified, - options - ), - entityId: null, - entityType: null, - everBeenUnlocked: null, - forcePasswordReset: null, - hasPremiumPersonally: null, - kdfIterations: await this.storageService.get( - v1Keys.kdfIterations, - options - ), - kdfType: await this.storageService.get(v1Keys.kdf, options), - keyHash: await this.storageService.get(v1Keys.keyHash, options), - lastActive: await this.storageService.get(v1Keys.lastActive, options), - lastSync: null, - userId: userId, - usesKeyConnector: null, - }, - settings: { - alwaysShowDock: await this.storageService.get( - v1Keys.alwaysShowDock, - options - ), - autoConfirmFingerPrints: await this.storageService.get( - v1Keys.autoConfirmFingerprints, - options - ), - autoFillOnPageLoadDefault: await this.storageService.get( - v1Keys.autoFillOnPageLoadDefault, - options - ), - biometricLocked: null, - biometricUnlock: await this.storageService.get( - v1Keys.biometricUnlock, - options - ), - clearClipboard: await this.storageService.get( - v1Keys.clearClipboard, - options - ), - defaultUriMatch: await this.storageService.get( - v1Keys.defaultUriMatch, - options - ), - disableAddLoginNotification: await this.storageService.get( - v1Keys.disableAddLoginNotification, - options - ), - disableAutoBiometricsPrompt: await this.storageService.get( - v1Keys.disableAutoBiometricsPrompt, - options - ), - disableAutoTotpCopy: await this.storageService.get( - v1Keys.disableAutoTotpCopy, - options - ), - disableBadgeCounter: await this.storageService.get( - v1Keys.disableBadgeCounter, - options - ), - disableChangedPasswordNotification: await this.storageService.get( - v1Keys.disableChangedPasswordNotification, - options - ), - disableContextMenuItem: await this.storageService.get( - v1Keys.disableContextMenuItem, - options - ), - disableGa: await this.storageService.get(v1Keys.disableGa, options), - dontShowCardsCurrentTab: await this.storageService.get( - v1Keys.dontShowCardsCurrentTab, - options - ), - dontShowIdentitiesCurrentTab: await this.storageService.get( - v1Keys.dontShowIdentitiesCurrentTab, - options - ), - enableAlwaysOnTop: await this.storageService.get( - v1Keys.enableAlwaysOnTop, - options - ), - enableAutoFillOnPageLoad: await this.storageService.get( - v1Keys.enableAutoFillOnPageLoad, - options - ), - enableBiometric: await this.storageService.get( - v1Keys.enableBiometric, - options - ), - enableBrowserIntegration: await this.storageService.get( - v1Keys.enableBrowserIntegration, - options - ), - enableBrowserIntegrationFingerprint: await this.storageService.get( - v1Keys.enableBrowserIntegrationFingerprint, - options - ), - enableCloseToTray: await this.storageService.get( - v1Keys.enableCloseToTray, - options - ), - enableFullWidth: await this.storageService.get( - v1Keys.enableFullWidth, - options - ), - enableGravitars: await this.storageService.get( - v1Keys.enableGravatars, - options - ), - enableMinimizeToTray: await this.storageService.get( - v1Keys.enableMinimizeToTray, - options - ), - enableStartToTray: await this.storageService.get( - v1Keys.enableStartToTray, - options - ), - enableTray: await this.storageService.get(v1Keys.enableTray, options), - environmentUrls: - (await this.storageService.get( - v1Keys.environmentUrls, - options - )) ?? new EnvironmentUrls(), - equivalentDomains: await this.storageService.get( - v1Keys.equivalentDomains, - options - ), - minimizeOnCopyToClipboard: await this.storageService.get( - v1Keys.minimizeOnCopyToClipboard, - options - ), - neverDomains: await this.storageService.get(v1Keys.neverDomains, options), - openAtLogin: await this.storageService.get(v1Keys.openAtLogin, options), - passwordGenerationOptions: await this.storageService.get( - v1Keys.passwordGenerationOptions, - options - ), - pinProtected: { - decrypted: null, - encrypted: await this.storageService.get(v1Keys.pinProtected, options), - }, - protectedPin: await this.storageService.get(v1Keys.protectedPin, options), - settings: await this.storageService.get( - v1KeyPrefixes.settings + userId, - options - ), - vaultTimeout: await this.storageService.get(v1Keys.vaultTimeout, options), - vaultTimeoutAction: await this.storageService.get( - v1Keys.vaultTimeoutAction, - options - ), - }, - tokens: { - accessToken: await this.storageService.get(v1Keys.accessToken, options), - decodedToken: null, - refreshToken: await this.storageService.get(v1Keys.refreshToken, options), - securityStamp: null, - }, - }), - }, - }; + await this.set(v1KeyPrefixes[keyPrefix] + userId, null); + } + } + }; - initialState.globals.environmentUrls = - (await this.storageService.get(v1Keys.environmentUrls, options)) ?? - new EnvironmentUrls(); - await this.storageService.save(keys.global, initialState.globals, options); - await this.storageService.save(keys.activeUserId, initialState.activeUserId, options); - if (initialState.activeUserId != null) { - await this.storageService.save( - initialState.activeUserId, - initialState.accounts[initialState.activeUserId] - ); + const globals: GlobalState = { + stateVersion: StateVersion.Two, + environmentUrls: + (await this.get(v1Keys.environmentUrls)) ?? new EnvironmentUrls(), + locale: await this.get(v1Keys.locale), + loginRedirect: null, + mainWindowSize: null, + noAutoPromptBiometrics: await this.get(v1Keys.disableAutoBiometricsPrompt), + noAutoPromptBiometricsText: await this.get(v1Keys.noAutoPromptBiometricsText), + openAtLogin: await this.get(v1Keys.openAtLogin), + organizationInvitation: null, + ssoCodeVerifier: await this.get(v1Keys.ssoCodeVerifier), + ssoOrganizationIdentifier: await this.get(v1Keys.ssoIdentifier), + ssoState: null, + rememberedEmail: await this.get(v1Keys.rememberedEmail), + theme: await this.get(v1Keys.theme), + vaultTimeout: await this.get(v1Keys.vaultTimeout), + vaultTimeoutAction: await this.get(v1Keys.vaultTimeoutAction), + window: null, + }; + + const userId = await this.get(v1Keys.userId); + + // (userId == null) = no logged in user (so no known userId) and we need to temporarily store account specific settings in state to migrate on first auth + // (userId != null) = we have a currently authed user (so known userId) with encrypted data and other key settings we can move, no need to temporarily store account settings + if (userId == null) { + await this.set(keys.tempAccountSettings, { + alwaysShowDock: await this.get(v1Keys.alwaysShowDock), + autoConfirmFingerPrints: await this.get(v1Keys.autoConfirmFingerprints), + autoFillOnPageLoadDefault: await this.get(v1Keys.autoFillOnPageLoadDefault), + biometricLocked: null, + biometricUnlock: await this.get(v1Keys.biometricUnlock), + clearClipboard: await this.get(v1Keys.clearClipboard), + defaultUriMatch: await this.get(v1Keys.defaultUriMatch), + disableAddLoginNotification: await this.get(v1Keys.disableAddLoginNotification), + disableAutoBiometricsPrompt: await this.get(v1Keys.disableAutoBiometricsPrompt), + disableAutoTotpCopy: await this.get(v1Keys.disableAutoTotpCopy), + disableBadgeCounter: await this.get(v1Keys.disableBadgeCounter), + disableChangedPasswordNotification: await this.get( + v1Keys.disableChangedPasswordNotification + ), + disableContextMenuItem: await this.get(v1Keys.disableContextMenuItem), + disableGa: await this.get(v1Keys.disableGa), + dontShowCardsCurrentTab: await this.get(v1Keys.dontShowCardsCurrentTab), + dontShowIdentitiesCurrentTab: await this.get(v1Keys.dontShowIdentitiesCurrentTab), + enableAlwaysOnTop: await this.get(v1Keys.enableAlwaysOnTop), + enableAutoFillOnPageLoad: await this.get(v1Keys.enableAutoFillOnPageLoad), + enableBiometric: await this.get(v1Keys.enableBiometric), + enableBrowserIntegration: await this.get(v1Keys.enableBrowserIntegration), + enableBrowserIntegrationFingerprint: await this.get( + v1Keys.enableBrowserIntegrationFingerprint + ), + enableCloseToTray: await this.get(v1Keys.enableCloseToTray), + enableFullWidth: await this.get(v1Keys.enableFullWidth), + enableGravitars: await this.get(v1Keys.enableGravatars), + enableMinimizeToTray: await this.get(v1Keys.enableMinimizeToTray), + enableStartToTray: await this.get(v1Keys.enableStartToTray), + enableTray: await this.get(v1Keys.enableTray), + environmentUrls: globals.environmentUrls, + equivalentDomains: await this.get(v1Keys.equivalentDomains), + minimizeOnCopyToClipboard: await this.get(v1Keys.minimizeOnCopyToClipboard), + neverDomains: await this.get(v1Keys.neverDomains), + openAtLogin: await this.get(v1Keys.openAtLogin), + passwordGenerationOptions: await this.get(v1Keys.passwordGenerationOptions), + pinProtected: { + decrypted: null, + encrypted: await this.get(v1Keys.pinProtected), + }, + protectedPin: await this.get(v1Keys.protectedPin), + settings: null, + vaultTimeout: await this.get(v1Keys.vaultTimeout), + vaultTimeoutAction: await this.get(v1Keys.vaultTimeoutAction), + }); + await this.set(keys.global, globals); + await this.set(keys.authenticatedAccounts, []); + await this.set(keys.activeUserId, null); + await clearV1Keys(); + return; } - await this.storageService.save(keys.authenticatedAccounts, initialState.authenticatedAccounts); + + globals.twoFactorToken = await this.get(v1KeyPrefixes.twoFactorToken + userId); + await this.set(keys.global, globals); + await this.set(userId, { + data: { + addEditCipherInfo: null, + ciphers: { + decrypted: null, + encrypted: await this.get<{ [id: string]: CipherData }>(v1KeyPrefixes.ciphers + userId), + }, + collapsedGroupings: null, + collections: { + decrypted: null, + encrypted: await this.get<{ [id: string]: CollectionData }>( + v1KeyPrefixes.collections + userId + ), + }, + eventCollection: await this.get(v1Keys.eventCollection), + folders: { + decrypted: null, + encrypted: await this.get<{ [id: string]: FolderData }>(v1KeyPrefixes.folders + userId), + }, + localData: null, + organizations: await this.get<{ [id: string]: OrganizationData }>( + v1KeyPrefixes.organizations + userId + ), + passwordGenerationHistory: { + decrypted: null, + encrypted: await this.get(v1Keys.history), + }, + policies: { + decrypted: null, + encrypted: await this.get<{ [id: string]: PolicyData }>(v1KeyPrefixes.policies + userId), + }, + providers: await this.get<{ [id: string]: ProviderData }>(v1KeyPrefixes.providers + userId), + sends: { + decrypted: null, + encrypted: await this.get<{ [id: string]: SendData }>(v1KeyPrefixes.sends + userId), + }, + }, + keys: { + apiKeyClientSecret: await this.get(v1Keys.clientSecret), + cryptoMasterKey: null, + cryptoMasterKeyAuto: null, + cryptoMasterKeyB64: null, + cryptoMasterKeyBiometric: null, + cryptoSymmetricKey: { + encrypted: await this.get(v1Keys.encKey), + decrypted: null, + }, + legacyEtmKey: null, + organizationKeys: { + decrypted: null, + encrypted: await this.get(v1Keys.encOrgKeys + userId), + }, + privateKey: { + decrypted: null, + encrypted: await this.get(v1Keys.encPrivate), + }, + providerKeys: { + decrypted: null, + encrypted: await this.get(v1Keys.encProviderKeys + userId), + }, + publicKey: null, + }, + profile: { + apiKeyClientId: await this.get(v1Keys.clientId), + authenticationStatus: null, + convertAccountToKeyConnector: await this.get(v1Keys.convertAccountToKeyConnector), + email: await this.get(v1Keys.userEmail), + emailVerified: await this.get(v1Keys.emailVerified), + entityId: null, + entityType: null, + everBeenUnlocked: null, + forcePasswordReset: null, + hasPremiumPersonally: null, + kdfIterations: await this.get(v1Keys.kdfIterations), + kdfType: await this.get(v1Keys.kdf), + keyHash: await this.get(v1Keys.keyHash), + lastActive: await this.get(v1Keys.lastActive), + lastSync: null, + userId: userId, + usesKeyConnector: null, + }, + settings: { + alwaysShowDock: await this.get(v1Keys.alwaysShowDock), + autoConfirmFingerPrints: await this.get(v1Keys.autoConfirmFingerprints), + autoFillOnPageLoadDefault: await this.get(v1Keys.autoFillOnPageLoadDefault), + biometricLocked: null, + biometricUnlock: await this.get(v1Keys.biometricUnlock), + clearClipboard: await this.get(v1Keys.clearClipboard), + defaultUriMatch: await this.get(v1Keys.defaultUriMatch), + disableAddLoginNotification: await this.get(v1Keys.disableAddLoginNotification), + disableAutoBiometricsPrompt: await this.get(v1Keys.disableAutoBiometricsPrompt), + disableAutoTotpCopy: await this.get(v1Keys.disableAutoTotpCopy), + disableBadgeCounter: await this.get(v1Keys.disableBadgeCounter), + disableChangedPasswordNotification: await this.get( + v1Keys.disableChangedPasswordNotification + ), + disableContextMenuItem: await this.get(v1Keys.disableContextMenuItem), + disableGa: await this.get(v1Keys.disableGa), + dontShowCardsCurrentTab: await this.get(v1Keys.dontShowCardsCurrentTab), + dontShowIdentitiesCurrentTab: await this.get(v1Keys.dontShowIdentitiesCurrentTab), + enableAlwaysOnTop: await this.get(v1Keys.enableAlwaysOnTop), + enableAutoFillOnPageLoad: await this.get(v1Keys.enableAutoFillOnPageLoad), + enableBiometric: await this.get(v1Keys.enableBiometric), + enableBrowserIntegration: await this.get(v1Keys.enableBrowserIntegration), + enableBrowserIntegrationFingerprint: await this.get( + v1Keys.enableBrowserIntegrationFingerprint + ), + enableCloseToTray: await this.get(v1Keys.enableCloseToTray), + enableFullWidth: await this.get(v1Keys.enableFullWidth), + enableGravitars: await this.get(v1Keys.enableGravatars), + enableMinimizeToTray: await this.get(v1Keys.enableMinimizeToTray), + enableStartToTray: await this.get(v1Keys.enableStartToTray), + enableTray: await this.get(v1Keys.enableTray), + environmentUrls: globals.environmentUrls, + equivalentDomains: await this.get(v1Keys.equivalentDomains), + minimizeOnCopyToClipboard: await this.get(v1Keys.minimizeOnCopyToClipboard), + neverDomains: await this.get(v1Keys.neverDomains), + openAtLogin: await this.get(v1Keys.openAtLogin), + passwordGenerationOptions: await this.get(v1Keys.passwordGenerationOptions), + pinProtected: { + decrypted: null, + encrypted: await this.get(v1Keys.pinProtected), + }, + protectedPin: await this.get(v1Keys.protectedPin), + settings: await this.get(v1KeyPrefixes.settings + userId), + vaultTimeout: await this.get(v1Keys.vaultTimeout), + vaultTimeoutAction: await this.get(v1Keys.vaultTimeoutAction), + }, + tokens: { + accessToken: await this.get(v1Keys.accessToken), + decodedToken: null, + refreshToken: await this.get(v1Keys.refreshToken), + securityStamp: null, + }, + }); + + await this.set(keys.authenticatedAccounts, [userId]); + await this.set(keys.activeUserId, userId); + await clearV1Keys(userId); if (await this.secureStorageService.has(v1Keys.key, { keySuffix: "biometric" })) { await this.secureStorageService.save( @@ -538,4 +415,27 @@ export class StateMigrationService { await this.secureStorageService.remove(v1Keys.key); } } + + private get options(): StorageOptions { + return { htmlStorageLocation: HtmlStorageLocation.Local }; + } + + private get(key: string): Promise { + return this.storageService.get(key, this.options); + } + + private set(key: string, value: any): Promise { + if (value == null) { + return this.storageService.remove(key, this.options); + } + return this.storageService.save(key, value, this.options); + } + + private async getGlobals(): Promise { + return await this.get(keys.global); + } + + private async getCurrentStateVersion(): Promise { + return (await this.getGlobals())?.stateVersion; + } }