mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
Migrate autoConfirmFingerPrints to StateProvider (#8337)
* Fix a typo in the `StateDefinition` description * Introduce `OrganizationManagementPreferencesService` * Declare `OrganizationManagementPreferencesService` in DI * Update `autoConfirmFingerPrints` logic in emergency access files * Update `autoConfirmFingerPrints` logic in `people` files * Remove `autoConfirmFingerPrints` from `StateService` and `Account` * Migrate existing client data for `autoConfirmFingerPrints` * Update apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Update apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts Co-authored-by: Matt Gibson <mgibson@bitwarden.com> * Use `set` instead of `update` for function names --------- Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
@@ -38,6 +38,7 @@ import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-
|
||||
import { OrganizationMigrator } from "./migrations/40-move-organization-state-to-state-provider";
|
||||
import { EventCollectionMigrator } from "./migrations/41-move-event-collection-to-state-provider";
|
||||
import { EnableFaviconMigrator } from "./migrations/42-move-enable-favicon-to-domain-settings-state-provider";
|
||||
import { AutoConfirmFingerPrintsMigrator } from "./migrations/43-move-auto-confirm-finger-prints-to-state-provider";
|
||||
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
||||
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
||||
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
||||
@@ -46,7 +47,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
||||
import { MinVersionMigrator } from "./migrations/min-version";
|
||||
|
||||
export const MIN_VERSION = 3;
|
||||
export const CURRENT_VERSION = 42;
|
||||
export const CURRENT_VERSION = 43;
|
||||
export type MinVersion = typeof MIN_VERSION;
|
||||
|
||||
export function createMigrationBuilder() {
|
||||
@@ -90,7 +91,8 @@ export function createMigrationBuilder() {
|
||||
.with(MoveBillingAccountProfileMigrator, 38, 39)
|
||||
.with(OrganizationMigrator, 39, 40)
|
||||
.with(EventCollectionMigrator, 40, 41)
|
||||
.with(EnableFaviconMigrator, 41, 42);
|
||||
.with(EnableFaviconMigrator, 41, 42)
|
||||
.with(AutoConfirmFingerPrintsMigrator, 42, CURRENT_VERSION);
|
||||
}
|
||||
|
||||
export async function currentVersion(
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { MigrationHelper } from "../migration-helper";
|
||||
import { mockMigrationHelper, runMigrator } from "../migration-helper.spec";
|
||||
|
||||
import { AutoConfirmFingerPrintsMigrator } from "./43-move-auto-confirm-finger-prints-to-state-provider";
|
||||
|
||||
function rollbackJSON() {
|
||||
return {
|
||||
authenticatedAccounts: ["user-1", "user-2"],
|
||||
"user_user-1_organizationManagementPreferences_autoConfirmFingerPrints": true,
|
||||
"user_user-2_organizationManagementPreferences_autoConfirmFingerPrints": false,
|
||||
"user-1": {
|
||||
settings: {
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
"user-2": {
|
||||
settings: {
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("AutoConfirmFingerPrintsMigrator", () => {
|
||||
const migrator = new AutoConfirmFingerPrintsMigrator(42, 43);
|
||||
|
||||
it("should migrate the autoConfirmFingerPrints property from the account settings object to a user StorageKey", async () => {
|
||||
const output = await runMigrator(migrator, {
|
||||
authenticatedAccounts: ["user-1", "user-2"] as const,
|
||||
"user-1": {
|
||||
settings: {
|
||||
autoConfirmFingerPrints: true,
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
"user-2": {
|
||||
settings: {
|
||||
autoConfirmFingerPrints: false,
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
});
|
||||
|
||||
expect(output).toEqual({
|
||||
authenticatedAccounts: ["user-1", "user-2"],
|
||||
"user_user-1_organizationManagementPreferences_autoConfirmFingerPrints": true,
|
||||
"user_user-2_organizationManagementPreferences_autoConfirmFingerPrints": false,
|
||||
"user-1": {
|
||||
settings: {
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
"user-2": {
|
||||
settings: {
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe("rollback", () => {
|
||||
let helper: MockProxy<MigrationHelper>;
|
||||
let sut: AutoConfirmFingerPrintsMigrator;
|
||||
|
||||
const keyDefinitionLike = {
|
||||
key: "autoConfirmFingerPrints",
|
||||
stateDefinition: {
|
||||
name: "organizationManagementPreferences",
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(rollbackJSON(), 43);
|
||||
sut = new AutoConfirmFingerPrintsMigrator(42, 43);
|
||||
});
|
||||
|
||||
it("should null the autoConfirmFingerPrints user StorageKey for each account", async () => {
|
||||
await sut.rollback(helper);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("user-1", keyDefinitionLike, null);
|
||||
});
|
||||
|
||||
it("should add the autoConfirmFingerPrints property back to the account settings object", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||
settings: {
|
||||
autoConfirmFingerPrints: true,
|
||||
extra: "data",
|
||||
},
|
||||
extra: "data",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { KeyDefinitionLike, MigrationHelper, StateDefinitionLike } from "../migration-helper";
|
||||
import { Migrator } from "../migrator";
|
||||
|
||||
type ExpectedAccountState = {
|
||||
settings?: { autoConfirmFingerPrints?: boolean };
|
||||
};
|
||||
|
||||
const ORGANIZATION_MANAGEMENT_PREFERENCES: StateDefinitionLike = {
|
||||
name: "organizationManagementPreferences",
|
||||
};
|
||||
|
||||
const AUTO_CONFIRM_FINGERPRINTS: KeyDefinitionLike = {
|
||||
key: "autoConfirmFingerPrints",
|
||||
stateDefinition: ORGANIZATION_MANAGEMENT_PREFERENCES,
|
||||
};
|
||||
|
||||
export class AutoConfirmFingerPrintsMigrator extends Migrator<42, 43> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
const legacyAccounts = await helper.getAccounts<ExpectedAccountState>();
|
||||
|
||||
await Promise.all(
|
||||
legacyAccounts.map(async ({ userId, account }) => {
|
||||
if (account?.settings?.autoConfirmFingerPrints != null) {
|
||||
await helper.setToUser(
|
||||
userId,
|
||||
AUTO_CONFIRM_FINGERPRINTS,
|
||||
account.settings.autoConfirmFingerPrints,
|
||||
);
|
||||
delete account?.settings?.autoConfirmFingerPrints;
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async rollback(helper: MigrationHelper): Promise<void> {
|
||||
async function rollbackUser(userId: string, account: ExpectedAccountState) {
|
||||
let updatedAccount = false;
|
||||
const autoConfirmFingerPrints = await helper.getFromUser<boolean>(
|
||||
userId,
|
||||
AUTO_CONFIRM_FINGERPRINTS,
|
||||
);
|
||||
|
||||
if (autoConfirmFingerPrints) {
|
||||
if (!account) {
|
||||
account = {};
|
||||
}
|
||||
|
||||
updatedAccount = true;
|
||||
account.settings.autoConfirmFingerPrints = autoConfirmFingerPrints;
|
||||
await helper.setToUser(userId, AUTO_CONFIRM_FINGERPRINTS, null);
|
||||
}
|
||||
|
||||
if (updatedAccount) {
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
}
|
||||
|
||||
const accounts = await helper.getAccounts<ExpectedAccountState>();
|
||||
|
||||
await Promise.all(accounts.map(({ userId, account }) => rollbackUser(userId, account)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user