diff --git a/common/src/enums/stateVersion.ts b/common/src/enums/stateVersion.ts new file mode 100644 index 0000000000..aa45edbbdd --- /dev/null +++ b/common/src/enums/stateVersion.ts @@ -0,0 +1,5 @@ +export enum StateVersion { + One = 1, // Original flat key/value pair store + Two = 2, // Move to a typed State object + Latest = Two, +} diff --git a/common/src/models/domain/account.ts b/common/src/models/domain/account.ts index cab08d1a9f..6a99813870 100644 --- a/common/src/models/domain/account.ts +++ b/common/src/models/domain/account.ts @@ -139,7 +139,7 @@ export class AccountSettings { protectedPin?: string; settings?: any; // TODO: Merge whatever is going on here into the AccountSettings model properly vaultTimeout?: number; - vaultTimeoutAction?: string; + vaultTimeoutAction?: string = "lock"; } export class AccountTokens { diff --git a/common/src/models/domain/globalState.ts b/common/src/models/domain/globalState.ts index 0fdce6486d..0dcf493902 100644 --- a/common/src/models/domain/globalState.ts +++ b/common/src/models/domain/globalState.ts @@ -1,15 +1,17 @@ +import { StateVersion } from "../../enums/stateVersion"; + export class GlobalState { enableAlwaysOnTop?: boolean; installedVersion?: string; lastActive?: number; - locale?: string; + locale?: string = "en"; openAtLogin?: boolean; organizationInvitation?: any; ssoCodeVerifier?: string; ssoOrganizationIdentifier?: string; ssoState?: string; rememberedEmail?: string; - theme?: string; + theme?: string = "light"; window?: Map = new Map(); twoFactorToken?: string; disableFavicon?: boolean; @@ -23,7 +25,7 @@ export class GlobalState { biometricText?: string; noAutoPromptBiometrics?: boolean; noAutoPromptBiometricsText?: string; - stateVersion: number; + stateVersion: StateVersion = StateVersion.Latest; environmentUrls?: any = { server: "bitwarden.com", }; diff --git a/common/src/services/state.service.ts b/common/src/services/state.service.ts index 5de1ccb18e..852809969d 100644 --- a/common/src/services/state.service.ts +++ b/common/src/services/state.service.ts @@ -74,7 +74,6 @@ export class StateService ); this.state = diskState; await this.pruneInMemoryAccounts(); - await this.saveStateToStorage(this.state, await this.defaultOnDiskMemoryOptions()); await this.pushAccounts(); } } diff --git a/common/src/services/stateMigration.service.ts b/common/src/services/stateMigration.service.ts index afe756e44b..7f36906e67 100644 --- a/common/src/services/stateMigration.service.ts +++ b/common/src/services/stateMigration.service.ts @@ -2,6 +2,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"; @@ -16,6 +17,7 @@ import { SendData } from "../models/data/sendData"; import { HtmlStorageLocation } from "../enums/htmlStorageLocation"; import { KdfType } from "../enums/kdfType"; +import { StateVersion } from "../enums/stateVersion"; // 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. @@ -111,8 +113,6 @@ const v1KeyPrefixes = { }; export class StateMigrationService { - readonly latestVersion: number = 2; - constructor( protected storageService: StorageService, protected secureStorageService: StorageService @@ -124,15 +124,16 @@ export class StateMigrationService { htmlStorageLocation: HtmlStorageLocation.Local, }) )?.globals?.stateVersion; - return currentStateVersion == null || currentStateVersion < this.latestVersion; + return currentStateVersion == null || currentStateVersion < StateVersion.Latest; } async migrate(): Promise { let currentStateVersion = - (await this.storageService.get>("state"))?.globals?.stateVersion ?? 1; - while (currentStateVersion < this.latestVersion) { + (await this.storageService.get>("state"))?.globals?.stateVersion ?? + StateVersion.One; + while (currentStateVersion < StateVersion.Latest) { switch (currentStateVersion) { - case 1: + case StateVersion.One: await this.migrateStateFrom1To2(); break; } @@ -147,9 +148,7 @@ export class StateMigrationService { const initialState: State = userId == null ? { - globals: { - stateVersion: 2, - }, + globals: new GlobalState(), accounts: {}, activeUserId: null, } @@ -209,7 +208,7 @@ export class StateMigrationService { v1Keys.rememberedEmail, options ), - stateVersion: 2, + stateVersion: StateVersion.Two, theme: await this.storageService.get(v1Keys.theme, options), twoFactorToken: await this.storageService.get( v1KeyPrefixes.twoFactorToken + userId,