1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

Add state for everHadUserKey (#7208)

* Migrate ever had user key

* Add DI for state providers

* Add state for everHadUserKey

* Use ever had user key migrator

Co-authored-by: SmithThe4th <gsmithwalter@gmail.com>
Co-authored-by: Carlos Gonçalves <LRNcardozoWDF@users.noreply.github.com>
Co-authored-by: Jason Ng <Jcory.ng@gmail.com>

* Fix test from merge

* Prefer stored observables to getters

getters create a new observable every time they're called, whereas one set in the constructor is created only once.

* Fix another merge issue

* Fix cli background build

---------

Co-authored-by: SmithThe4th <gsmithwalter@gmail.com>
Co-authored-by: Carlos Gonçalves <LRNcardozoWDF@users.noreply.github.com>
Co-authored-by: Jason Ng <Jcory.ng@gmail.com>
This commit is contained in:
Matt Gibson
2024-01-10 11:51:45 -05:00
committed by GitHub
parent 211d7a2626
commit 46a3834f46
21 changed files with 404 additions and 100 deletions

View File

@@ -5,6 +5,7 @@ import { AbstractStorageService } from "../platform/abstractions/storage.service
import { MigrationBuilder } from "./migration-builder";
import { MigrationHelper } from "./migration-helper";
import { EverHadUserKeyMigrator } from "./migrations/10-move-ever-had-user-key-to-state-providers";
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";
@@ -15,7 +16,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
import { MinVersionMigrator } from "./migrations/min-version";
export const MIN_VERSION = 2;
export const CURRENT_VERSION = 9;
export const CURRENT_VERSION = 10;
export type MinVersion = typeof MIN_VERSION;
export async function migrate(
@@ -40,7 +41,8 @@ export async function migrate(
.with(RemoveLegacyEtmKeyMigrator, 5, 6)
.with(MoveBiometricAutoPromptToAccount, 6, 7)
.with(MoveStateVersionMigrator, 7, 8)
.with(MoveBrowserSettingsToGlobal, 8, CURRENT_VERSION)
.with(MoveBrowserSettingsToGlobal, 8, 9)
.with(EverHadUserKeyMigrator, 9, CURRENT_VERSION)
.migrate(migrationHelper);
}

View File

@@ -0,0 +1,161 @@
import { MockProxy, any } from "jest-mock-extended";
import { MigrationHelper } from "../migration-helper";
import { mockMigrationHelper } from "../migration-helper.spec";
import { EverHadUserKeyMigrator } from "./10-move-ever-had-user-key-to-state-providers";
function exampleJSON() {
return {
global: {
otherStuff: "otherStuff1",
},
authenticatedAccounts: [
"c493ed01-4e08-4e88-abc7-332f380ca760",
"23e61a5f-2ece-4f5e-b499-f0bc489482a9",
"fd005ea6-a16a-45ef-ba4a-a194269bfd73",
],
"c493ed01-4e08-4e88-abc7-332f380ca760": {
profile: {
everHadUserKey: false,
otherStuff: "overStuff2",
},
otherStuff: "otherStuff3",
},
"23e61a5f-2ece-4f5e-b499-f0bc489482a9": {
profile: {
everHadUserKey: true,
otherStuff: "otherStuff4",
},
otherStuff: "otherStuff5",
},
};
}
function rollbackJSON() {
return {
"user_c493ed01-4e08-4e88-abc7-332f380ca760_crypto_everHadUserKey": false,
"user_23e61a5f-2ece-4f5e-b499-f0bc489482a9_crypto_everHadUserKey": true,
"user_fd005ea6-a16a-45ef-ba4a-a194269bfd73_crypto_everHadUserKey": false,
global: {
otherStuff: "otherStuff1",
},
authenticatedAccounts: [
"c493ed01-4e08-4e88-abc7-332f380ca760",
"23e61a5f-2ece-4f5e-b499-f0bc489482a9",
"fd005ea6-a16a-45ef-ba4a-a194269bfd73",
],
"c493ed01-4e08-4e88-abc7-332f380ca760": {
profile: {
everHadUserKey: false,
otherStuff: "overStuff2",
},
otherStuff: "otherStuff3",
},
"23e61a5f-2ece-4f5e-b499-f0bc489482a9": {
profile: {
everHadUserKey: true,
otherStuff: "otherStuff4",
},
otherStuff: "otherStuff5",
},
};
}
describe("EverHadUserKeyMigrator", () => {
let helper: MockProxy<MigrationHelper>;
let sut: EverHadUserKeyMigrator;
const keyDefinitionLike = {
key: "everHadUserKey",
stateDefinition: {
name: "crypto",
},
};
describe("migrate", () => {
beforeEach(() => {
helper = mockMigrationHelper(exampleJSON(), 9);
sut = new EverHadUserKeyMigrator(9, 10);
});
it("should remove everHadUserKey from all accounts", async () => {
await sut.migrate(helper);
expect(helper.set).toHaveBeenCalledWith("c493ed01-4e08-4e88-abc7-332f380ca760", {
profile: {
otherStuff: "overStuff2",
},
otherStuff: "otherStuff3",
});
expect(helper.set).toHaveBeenCalledWith("23e61a5f-2ece-4f5e-b499-f0bc489482a9", {
profile: {
otherStuff: "otherStuff4",
},
otherStuff: "otherStuff5",
});
});
it("should set everHadUserKey provider value for each account", async () => {
await sut.migrate(helper);
expect(helper.setToUser).toHaveBeenCalledWith(
"c493ed01-4e08-4e88-abc7-332f380ca760",
keyDefinitionLike,
false,
);
expect(helper.setToUser).toHaveBeenCalledWith(
"23e61a5f-2ece-4f5e-b499-f0bc489482a9",
keyDefinitionLike,
true,
);
expect(helper.setToUser).toHaveBeenCalledWith(
"fd005ea6-a16a-45ef-ba4a-a194269bfd73",
keyDefinitionLike,
false,
);
});
});
describe("rollback", () => {
beforeEach(() => {
helper = mockMigrationHelper(rollbackJSON(), 10);
sut = new EverHadUserKeyMigrator(9, 10);
});
it.each([
"c493ed01-4e08-4e88-abc7-332f380ca760",
"23e61a5f-2ece-4f5e-b499-f0bc489482a9",
"fd005ea6-a16a-45ef-ba4a-a194269bfd73",
])("should null out new values", async (userId) => {
await sut.rollback(helper);
expect(helper.setToUser).toHaveBeenCalledWith(userId, keyDefinitionLike, null);
});
it("should add explicit value back to accounts", async () => {
await sut.rollback(helper);
expect(helper.set).toHaveBeenCalledWith("c493ed01-4e08-4e88-abc7-332f380ca760", {
profile: {
everHadUserKey: false,
otherStuff: "overStuff2",
},
otherStuff: "otherStuff3",
});
expect(helper.set).toHaveBeenCalledWith("23e61a5f-2ece-4f5e-b499-f0bc489482a9", {
profile: {
everHadUserKey: true,
otherStuff: "otherStuff4",
},
otherStuff: "otherStuff5",
});
});
it("should not try to restore values to missing accounts", async () => {
await sut.rollback(helper);
expect(helper.set).not.toHaveBeenCalledWith("fd005ea6-a16a-45ef-ba4a-a194269bfd73", any());
});
});
});

View File

@@ -0,0 +1,46 @@
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
import { Migrator } from "../migrator";
type ExpectedAccountType = {
profile?: {
everHadUserKey?: boolean;
};
};
const USER_EVER_HAD_USER_KEY: KeyDefinitionLike = {
key: "everHadUserKey",
stateDefinition: {
name: "crypto",
},
};
export class EverHadUserKeyMigrator extends Migrator<9, 10> {
async migrate(helper: MigrationHelper): Promise<void> {
const accounts = await helper.getAccounts<ExpectedAccountType>();
async function migrateAccount(userId: string, account: ExpectedAccountType): Promise<void> {
const value = account?.profile?.everHadUserKey;
await helper.setToUser(userId, USER_EVER_HAD_USER_KEY, value ?? false);
if (value != null) {
delete account.profile.everHadUserKey;
}
await helper.set(userId, account);
}
await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]);
}
async rollback(helper: MigrationHelper): Promise<void> {
const accounts = await helper.getAccounts<ExpectedAccountType>();
async function rollbackAccount(userId: string, account: ExpectedAccountType): Promise<void> {
const value = await helper.getFromUser(userId, USER_EVER_HAD_USER_KEY);
if (account) {
account.profile = Object.assign(account.profile ?? {}, {
everHadUserKey: value,
});
await helper.set(userId, account);
}
await helper.setToUser(userId, USER_EVER_HAD_USER_KEY, null);
}
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
}
}