bitwarden-estensione-browser/libs/common/src/state-migrations/migrations/60-move-pin-state-to-provid...

127 lines
3.8 KiB
TypeScript

import { KeyDefinitionLike, MigrationHelper, StateDefinitionLike } from "../migration-helper";
import { Migrator } from "../migrator";
type ExpectedAccountState = {
settings?: {
pinKeyEncryptedUserKey?: string; // EncryptedString
protectedPin?: string;
pinProtected?: {
encrypted?: string;
};
};
};
export const PIN_STATE: StateDefinitionLike = { name: "pinUnlock" };
export const PIN_KEY_ENCRYPTED_USER_KEY: KeyDefinitionLike = {
stateDefinition: PIN_STATE,
key: "pinKeyEncryptedUserKey",
};
export const PROTECTED_PIN: KeyDefinitionLike = {
stateDefinition: PIN_STATE,
key: "protectedPin",
};
export const OLD_PIN_KEY_ENCRYPTED_MASTER_KEY: KeyDefinitionLike = {
stateDefinition: PIN_STATE,
key: "oldPinKeyEncryptedMasterKey",
};
export class PinStateMigrator extends Migrator<59, 60> {
async migrate(helper: MigrationHelper): Promise<void> {
const legacyAccounts = await helper.getAccounts<ExpectedAccountState>();
let updatedAccount = false;
async function migrateAccount(userId: string, account: ExpectedAccountState) {
// Migrate pinKeyEncryptedUserKey
if (account?.settings?.pinKeyEncryptedUserKey != null) {
await helper.setToUser(
userId,
PIN_KEY_ENCRYPTED_USER_KEY,
account.settings.pinKeyEncryptedUserKey,
);
delete account.settings.pinKeyEncryptedUserKey;
updatedAccount = true;
}
// Migrate protectedPin
if (account?.settings?.protectedPin != null) {
await helper.setToUser(userId, PROTECTED_PIN, account.settings.protectedPin);
delete account.settings.protectedPin;
updatedAccount = true;
}
// Migrate pinProtected
if (account?.settings?.pinProtected?.encrypted != null) {
await helper.setToUser(
userId,
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
account.settings.pinProtected.encrypted,
);
delete account.settings.pinProtected;
updatedAccount = true;
}
if (updatedAccount) {
await helper.set(userId, account);
}
}
await Promise.all([
...legacyAccounts.map(({ userId, account }) => migrateAccount(userId, account)),
]);
}
async rollback(helper: MigrationHelper): Promise<void> {
const accounts = await helper.getAccounts<ExpectedAccountState>();
async function rollbackAccount(userId: string, account: ExpectedAccountState) {
let updatedAccount = false;
const accountPinKeyEncryptedUserKey = await helper.getFromUser<string>(
userId,
PIN_KEY_ENCRYPTED_USER_KEY,
);
const accountProtectedPin = await helper.getFromUser<string>(userId, PROTECTED_PIN);
const accountOldPinKeyEncryptedMasterKey = await helper.getFromUser<string>(
userId,
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
);
if (!account) {
account = {};
}
if (accountPinKeyEncryptedUserKey != null) {
account.settings.pinKeyEncryptedUserKey = accountPinKeyEncryptedUserKey;
await helper.setToUser(userId, PIN_KEY_ENCRYPTED_USER_KEY, null);
updatedAccount = true;
}
if (accountProtectedPin != null) {
account.settings.protectedPin = accountProtectedPin;
await helper.setToUser(userId, PROTECTED_PIN, null);
updatedAccount = true;
}
if (accountOldPinKeyEncryptedMasterKey != null) {
account.settings = Object.assign(account.settings ?? {}, {
pinProtected: {
encrypted: accountOldPinKeyEncryptedMasterKey,
},
});
await helper.setToUser(userId, OLD_PIN_KEY_ENCRYPTED_MASTER_KEY, null);
updatedAccount = true;
}
if (updatedAccount) {
await helper.set(userId, account);
}
}
await Promise.all(accounts.map(({ userId, account }) => rollbackAccount(userId, account)));
}
}