1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 17:53:39 +00:00
Files
browser/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts
Matt Gibson 9c1e2ebd67 Typescript-strict-plugin (#12235)
* Use typescript-strict-plugin to iteratively turn on strict

* Add strict testing to pipeline

Can be executed locally through either `npm run test:types` for full type checking including spec files, or `npx tsc-strict` for only tsconfig.json included files.

* turn on strict for scripts directory

* Use plugin for all tsconfigs in monorepo

vscode is capable of executing tsc with plugins, but uses the most relevant tsconfig to do so. If the plugin is not a part of that config, it is skipped and developers get no feedback of strict compile time issues. These updates remedy that at the cost of slightly more complex removal of the plugin when the time comes.

* remove plugin from configs that extend one that already has it

* Update workspace settings to honor strict plugin

* Apply strict-plugin to native message test runner

* Update vscode workspace to use root tsc version

* `./node_modules/.bin/update-strict-comments` 🤖

This is a one-time operation. All future files should adhere to strict type checking.

* Add fixme to `ts-strict-ignore` comments

* `update-strict-comments` 🤖

repeated for new merge files
2024-12-09 20:58:50 +01:00

182 lines
6.2 KiB
TypeScript

// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { KeyDefinitionLike, MigrationHelper, StateDefinitionLike } from "../migration-helper";
import { Migrator } from "../migrator";
// Types to represent data as it is stored in JSON
type ExpectedAccountType = {
settings?: {
vaultTimeout?: number;
vaultTimeoutAction?: string;
};
};
type ExpectedGlobalType = {
vaultTimeout?: number;
vaultTimeoutAction?: string;
};
const VAULT_TIMEOUT_SETTINGS_STATE_DEF_LIKE: StateDefinitionLike = {
name: "vaultTimeoutSettings",
};
export const VAULT_TIMEOUT: KeyDefinitionLike = {
key: "vaultTimeout", // matches KeyDefinition.key
stateDefinition: VAULT_TIMEOUT_SETTINGS_STATE_DEF_LIKE,
};
export const VAULT_TIMEOUT_ACTION: KeyDefinitionLike = {
key: "vaultTimeoutAction", // matches KeyDefinition.key
stateDefinition: VAULT_TIMEOUT_SETTINGS_STATE_DEF_LIKE,
};
// Migrations are supposed to be frozen so we have to copy the type here.
export type VaultTimeout =
| number // 0 for immediately; otherwise positive numbers
| "never" // null
| "onRestart" // -1
| "onLocked" // -2
| "onSleep" // -3
| "onIdle"; // -4
// Define mapping of old values to new values for migration purposes
const vaultTimeoutTypeMigrateRecord: Record<any, VaultTimeout> = {
null: "never",
"-1": "onRestart",
"-2": "onLocked",
"-3": "onSleep",
"-4": "onIdle",
};
// define mapping of new values to old values for rollback purposes
const vaultTimeoutTypeRollbackRecord: Record<VaultTimeout, any> = {
never: null,
onRestart: -1,
onLocked: -2,
onSleep: -3,
onIdle: -4,
};
export enum ClientType {
Web = "web",
Browser = "browser",
Desktop = "desktop",
Cli = "cli",
}
export class VaultTimeoutSettingsServiceStateProviderMigrator extends Migrator<61, 62> {
async migrate(helper: MigrationHelper): Promise<void> {
const globalData = await helper.get<ExpectedGlobalType>("global");
const accounts = await helper.getAccounts<ExpectedAccountType>();
async function migrateAccount(
userId: string,
account: ExpectedAccountType | undefined,
): Promise<void> {
let updatedAccount = false;
// Migrate vault timeout
let existingVaultTimeout = account?.settings?.vaultTimeout;
if (helper.clientType === ClientType.Cli && existingVaultTimeout === undefined) {
// The CLI does not set a vault timeout by default so we need to set it to null
// so that the migration can migrate null to "never" as the CLI does not have a vault timeout.
existingVaultTimeout = null;
}
if (existingVaultTimeout !== undefined) {
// check undefined so that we allow null values (previously meant never timeout)
// Only migrate data that exists
if (existingVaultTimeout === null || existingVaultTimeout < 0) {
// Map null or negative values to new string values
const newVaultTimeout = vaultTimeoutTypeMigrateRecord[existingVaultTimeout];
await helper.setToUser(userId, VAULT_TIMEOUT, newVaultTimeout);
} else {
// Persist positive numbers as is
await helper.setToUser(userId, VAULT_TIMEOUT, existingVaultTimeout);
}
delete account?.settings?.vaultTimeout;
updatedAccount = true;
}
// Migrate vault timeout action
const existingVaultTimeoutAction = account?.settings?.vaultTimeoutAction;
if (existingVaultTimeoutAction != null) {
// Only migrate data that exists
await helper.setToUser(userId, VAULT_TIMEOUT_ACTION, existingVaultTimeoutAction);
delete account?.settings?.vaultTimeoutAction;
updatedAccount = true;
}
// Note: we are explicitly not worrying about mapping over the global fallback vault timeout / action
// into the new state provider framework. It was originally a fallback but hasn't been used for years
// so this migration will clean up the global properties fully.
if (updatedAccount) {
// Save the migrated account only if it was updated
await helper.set(userId, account);
}
}
await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]);
// Delete global data (works for browser extension and web; CLI doesn't have these as global settings).
delete globalData?.vaultTimeout;
delete globalData?.vaultTimeoutAction;
await helper.set("global", globalData);
// Remove desktop only settings. These aren't found by the above global key removal b/c of
// the different storage key format. This removal does not cause any issues on migrating for other clients.
await helper.remove("global\\.vaultTimeout");
await helper.remove("global\\.vaultTimeoutAction");
}
async rollback(helper: MigrationHelper): Promise<void> {
const accounts = await helper.getAccounts<ExpectedAccountType>();
async function rollbackAccount(userId: string, account: ExpectedAccountType): Promise<void> {
let updatedLegacyAccount = false;
// Rollback vault timeout
const migratedVaultTimeout = await helper.getFromUser<VaultTimeout>(userId, VAULT_TIMEOUT);
if (account?.settings && migratedVaultTimeout != null) {
if (typeof migratedVaultTimeout === "string") {
// Map new string values back to old values
account.settings.vaultTimeout = vaultTimeoutTypeRollbackRecord[migratedVaultTimeout];
} else {
// persist numbers as is
account.settings.vaultTimeout = migratedVaultTimeout;
}
updatedLegacyAccount = true;
}
await helper.setToUser(userId, VAULT_TIMEOUT, null);
// Rollback vault timeout action
const migratedVaultTimeoutAction = await helper.getFromUser<string>(
userId,
VAULT_TIMEOUT_ACTION,
);
if (account?.settings && migratedVaultTimeoutAction != null) {
account.settings.vaultTimeoutAction = migratedVaultTimeoutAction;
updatedLegacyAccount = true;
}
await helper.setToUser(userId, VAULT_TIMEOUT_ACTION, null);
if (updatedLegacyAccount) {
await helper.set(userId, account);
}
}
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
}
}