mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 17:53:39 +00:00
* 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
182 lines
6.2 KiB
TypeScript
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))]);
|
|
}
|
|
}
|