mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-25 12:15:18 +01:00
Include missing migration (#7840)
This migration missing from #7825 does not suggest missing data since no client has been released in the interim.
This commit is contained in:
parent
e5d4d4ad00
commit
7a6d7b3a68
@ -13,6 +13,7 @@ import { FolderMigrator } from "./migrations/15-move-folder-state-to-state-provi
|
||||
import { LastSyncMigrator } from "./migrations/16-move-last-sync-to-state-provider";
|
||||
import { EnablePasskeysMigrator } from "./migrations/17-move-enable-passkeys-to-state-providers";
|
||||
import { AutofillSettingsKeyMigrator } from "./migrations/18-move-autofill-settings-to-state-providers";
|
||||
import { RequirePasswordOnStartMigrator } from "./migrations/19-migrate-require-password-on-start";
|
||||
import { FixPremiumMigrator } from "./migrations/3-fix-premium";
|
||||
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
||||
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
||||
@ -23,7 +24,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
||||
import { MinVersionMigrator } from "./migrations/min-version";
|
||||
|
||||
export const MIN_VERSION = 2;
|
||||
export const CURRENT_VERSION = 18;
|
||||
export const CURRENT_VERSION = 19;
|
||||
export type MinVersion = typeof MIN_VERSION;
|
||||
|
||||
export function createMigrationBuilder() {
|
||||
@ -44,7 +45,8 @@ export function createMigrationBuilder() {
|
||||
.with(FolderMigrator, 14, 15)
|
||||
.with(LastSyncMigrator, 15, 16)
|
||||
.with(EnablePasskeysMigrator, 16, 17)
|
||||
.with(AutofillSettingsKeyMigrator, 17, CURRENT_VERSION);
|
||||
.with(AutofillSettingsKeyMigrator, 17, 18)
|
||||
.with(RequirePasswordOnStartMigrator, 18, CURRENT_VERSION);
|
||||
}
|
||||
|
||||
export async function currentVersion(
|
||||
|
@ -0,0 +1,123 @@
|
||||
import { MockProxy, any } from "jest-mock-extended";
|
||||
|
||||
import { MigrationHelper } from "../migration-helper";
|
||||
import { mockMigrationHelper } from "../migration-helper.spec";
|
||||
|
||||
import {
|
||||
REQUIRE_PASSWORD_ON_START,
|
||||
RequirePasswordOnStartMigrator,
|
||||
} from "./19-migrate-require-password-on-start";
|
||||
|
||||
function exampleJSON() {
|
||||
return {
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["user-1", "user-2", "user-3"],
|
||||
"user-1": {
|
||||
settings: {
|
||||
requirePasswordOnStart: true,
|
||||
otherStuff: "overStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
"user-2": {
|
||||
keys: {
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function rollbackJSON() {
|
||||
return {
|
||||
"user_user-1_biometricSettings_requirePasswordOnStart": true,
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["user-1", "user-2", "user-3"],
|
||||
"user-1": {
|
||||
settings: {
|
||||
otherStuff: "overStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
"user-2": {
|
||||
keys: {
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("DesktopBiometricState migrator", () => {
|
||||
let helper: MockProxy<MigrationHelper>;
|
||||
let sut: RequirePasswordOnStartMigrator;
|
||||
|
||||
describe("migrate", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(exampleJSON(), 18);
|
||||
sut = new RequirePasswordOnStartMigrator(18, 19);
|
||||
});
|
||||
|
||||
it("should remove biometricEncryptionClientKeyHalf from all accounts", async () => {
|
||||
await sut.migrate(helper);
|
||||
expect(helper.set).toHaveBeenCalledTimes(1);
|
||||
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||
settings: {
|
||||
otherStuff: "overStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
});
|
||||
});
|
||||
|
||||
it("should set biometricEncryptionClientKeyHalf value for account that have it", async () => {
|
||||
await sut.migrate(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("user-1", REQUIRE_PASSWORD_ON_START, true);
|
||||
});
|
||||
|
||||
it("should not call extra setToUser", async () => {
|
||||
await sut.migrate(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("rollback", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(rollbackJSON(), 19);
|
||||
sut = new RequirePasswordOnStartMigrator(18, 19);
|
||||
});
|
||||
|
||||
it("should null out new values", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("user-1", REQUIRE_PASSWORD_ON_START, null);
|
||||
});
|
||||
|
||||
it("should add explicit value back to accounts", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.set).toHaveBeenCalledTimes(1);
|
||||
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||
settings: {
|
||||
requirePasswordOnStart: true,
|
||||
otherStuff: "overStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["user-2", "user-3"])(
|
||||
"should not try to restore values to missing accounts",
|
||||
async (userId) => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.set).not.toHaveBeenCalledWith(userId, any());
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
@ -0,0 +1,56 @@
|
||||
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||
import { Migrator } from "../migrator";
|
||||
|
||||
type ExpectedAccountType = {
|
||||
settings?: {
|
||||
requirePasswordOnStart?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
// Biometric text, no auto prompt text, fingerprint validated, and prompt cancelled are refreshed on every app start, so we don't need to migrate them
|
||||
export const REQUIRE_PASSWORD_ON_START: KeyDefinitionLike = {
|
||||
key: "requirePasswordOnStart",
|
||||
stateDefinition: { name: "biometricSettings" },
|
||||
};
|
||||
|
||||
export class RequirePasswordOnStartMigrator extends Migrator<18, 19> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
const legacyAccounts = await helper.getAccounts<ExpectedAccountType>();
|
||||
|
||||
await Promise.all(
|
||||
legacyAccounts.map(async ({ userId, account }) => {
|
||||
// Move account data
|
||||
if (account?.settings?.requirePasswordOnStart != null) {
|
||||
await helper.setToUser(
|
||||
userId,
|
||||
REQUIRE_PASSWORD_ON_START,
|
||||
account.settings.requirePasswordOnStart,
|
||||
);
|
||||
|
||||
// Delete old account data
|
||||
delete account.settings.requirePasswordOnStart;
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async rollback(helper: MigrationHelper): Promise<void> {
|
||||
async function rollbackUser(userId: string, account: ExpectedAccountType) {
|
||||
const requirePassword = await helper.getFromUser<boolean>(userId, REQUIRE_PASSWORD_ON_START);
|
||||
|
||||
if (requirePassword) {
|
||||
account ??= {};
|
||||
account.settings ??= {};
|
||||
|
||||
account.settings.requirePasswordOnStart = requirePassword;
|
||||
await helper.setToUser(userId, REQUIRE_PASSWORD_ON_START, null);
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
}
|
||||
|
||||
const accounts = await helper.getAccounts<ExpectedAccountType>();
|
||||
|
||||
await Promise.all(accounts.map(({ userId, account }) => rollbackUser(userId, account)));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user