mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 01:03:35 +00:00
[PM-5572] Event upload and collection state provider migration (#7863)
* event upload and collection state provider migration * cipher can be null when exporting org * Addressing pr comments. Casting UserId from calling methods * fixing userAuth observable in event collection service * Adding more documentation for the changes. * cli needed state provider and account services added * Addressing pr comments on modifying should update * No need to auth on event upload * Simplifying the takeEvents for pulling user events * Reverting shouldUpdate to previous state * Removing redundant comment * Removing account service for event upload * Modifying the shouldUpdate to evaluate the logic outside of the observable * Adding back in the auth for event upload service and adding event upload to the cli logout method * Adding the browser service factories * Updating the browser services away from get background * Removing event collect and upload services from browser services * Removing the audit service import * Adding the event collection migration and migration test * Event collection state needs to be stored on disk * removing event collection from state service and abstraction * removing event collection from the account data * Saving the migrations themselves
This commit is contained in:
@@ -36,6 +36,7 @@ import { TokenServiceStateProviderMigrator } from "./migrations/38-migrate-token
|
||||
import { MoveBillingAccountProfileMigrator } from "./migrations/39-move-billing-account-profile-to-state-providers";
|
||||
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
||||
import { OrganizationMigrator } from "./migrations/40-move-organization-state-to-state-provider";
|
||||
import { EventCollectionMigrator } from "./migrations/41-move-event-collection-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";
|
||||
@@ -44,7 +45,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
||||
import { MinVersionMigrator } from "./migrations/min-version";
|
||||
|
||||
export const MIN_VERSION = 3;
|
||||
export const CURRENT_VERSION = 40;
|
||||
export const CURRENT_VERSION = 41;
|
||||
export type MinVersion = typeof MIN_VERSION;
|
||||
|
||||
export function createMigrationBuilder() {
|
||||
@@ -86,7 +87,8 @@ export function createMigrationBuilder() {
|
||||
.with(AvatarColorMigrator, 36, 37)
|
||||
.with(TokenServiceStateProviderMigrator, 37, 38)
|
||||
.with(MoveBillingAccountProfileMigrator, 38, 39)
|
||||
.with(OrganizationMigrator, 39, CURRENT_VERSION);
|
||||
.with(OrganizationMigrator, 39, 40)
|
||||
.with(EventCollectionMigrator, 40, CURRENT_VERSION);
|
||||
}
|
||||
|
||||
export async function currentVersion(
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import { MockProxy, any } from "jest-mock-extended";
|
||||
|
||||
import { MigrationHelper } from "../migration-helper";
|
||||
import { mockMigrationHelper } from "../migration-helper.spec";
|
||||
|
||||
import { EventCollectionMigrator } from "./41-move-event-collection-to-state-provider";
|
||||
|
||||
function exampleJSON() {
|
||||
return {
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["user-1", "user-2"],
|
||||
"user-1": {
|
||||
data: {
|
||||
eventCollection: [
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "5154f91d-c469-4d23-aefa-b12a0140d684",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T21:59:50.169Z",
|
||||
},
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "ed4661bd-412c-4b05-89a2-b12a01697a2c",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T22:02:06.089Z",
|
||||
},
|
||||
],
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
"user-2": {
|
||||
data: {
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function rollbackJSON() {
|
||||
return {
|
||||
"user_user-1_eventCollection_eventCollection": [
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "5154f91d-c469-4d23-aefa-b12a0140d684",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T21:59:50.169Z",
|
||||
},
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "ed4661bd-412c-4b05-89a2-b12a01697a2c",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T22:02:06.089Z",
|
||||
},
|
||||
],
|
||||
"user_user-2_eventCollection_data": null as any,
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["user-1", "user-2"],
|
||||
"user-1": {
|
||||
data: {
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
"user-2": {
|
||||
data: {
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("EventCollectionMigrator", () => {
|
||||
let helper: MockProxy<MigrationHelper>;
|
||||
let sut: EventCollectionMigrator;
|
||||
const keyDefinitionLike = {
|
||||
stateDefinition: {
|
||||
name: "eventCollection",
|
||||
},
|
||||
key: "eventCollection",
|
||||
};
|
||||
|
||||
describe("migrate", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(exampleJSON(), 40);
|
||||
sut = new EventCollectionMigrator(40, 41);
|
||||
});
|
||||
|
||||
it("should remove event collections from all accounts", async () => {
|
||||
await sut.migrate(helper);
|
||||
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||
data: {
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
});
|
||||
});
|
||||
|
||||
it("should set event collections for each account", async () => {
|
||||
await sut.migrate(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("user-1", keyDefinitionLike, [
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "5154f91d-c469-4d23-aefa-b12a0140d684",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T21:59:50.169Z",
|
||||
},
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "ed4661bd-412c-4b05-89a2-b12a01697a2c",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T22:02:06.089Z",
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("rollback", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(rollbackJSON(), 41);
|
||||
sut = new EventCollectionMigrator(40, 41);
|
||||
});
|
||||
|
||||
it.each(["user-1", "user-2"])("should null out new values", async (userId) => {
|
||||
await sut.rollback(helper);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith(userId, keyDefinitionLike, null);
|
||||
});
|
||||
|
||||
it("should add event collection values back to accounts", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.set).toHaveBeenCalled();
|
||||
expect(helper.set).toHaveBeenCalledWith("user-1", {
|
||||
data: {
|
||||
eventCollection: [
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "5154f91d-c469-4d23-aefa-b12a0140d684",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T21:59:50.169Z",
|
||||
},
|
||||
{
|
||||
type: 1107,
|
||||
cipherId: "ed4661bd-412c-4b05-89a2-b12a01697a2c",
|
||||
organizationId: "278d5f91-835b-459a-a229-b11e01336d6d",
|
||||
date: "2024-03-05T22:02:06.089Z",
|
||||
},
|
||||
],
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
});
|
||||
});
|
||||
|
||||
it("should not try to restore values to missing accounts", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.set).not.toHaveBeenCalledWith("user-3", any());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||
import { Migrator } from "../migrator";
|
||||
|
||||
type ExpectedAccountState = {
|
||||
data?: {
|
||||
eventCollection?: [];
|
||||
};
|
||||
};
|
||||
|
||||
const EVENT_COLLECTION: KeyDefinitionLike = {
|
||||
stateDefinition: {
|
||||
name: "eventCollection",
|
||||
},
|
||||
key: "eventCollection",
|
||||
};
|
||||
|
||||
export class EventCollectionMigrator extends Migrator<40, 41> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
const accounts = await helper.getAccounts<ExpectedAccountState>();
|
||||
|
||||
async function migrateAccount(userId: string, account: ExpectedAccountState): Promise<void> {
|
||||
const value = account?.data?.eventCollection;
|
||||
if (value != null) {
|
||||
await helper.setToUser(userId, EVENT_COLLECTION, value);
|
||||
delete account.data.eventCollection;
|
||||
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<ExpectedAccountState>();
|
||||
|
||||
async function rollbackAccount(userId: string, account: ExpectedAccountState): Promise<void> {
|
||||
const value = await helper.getFromUser(userId, EVENT_COLLECTION);
|
||||
if (account) {
|
||||
account.data = Object.assign(account.data ?? {}, {
|
||||
eventCollection: value,
|
||||
});
|
||||
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
await helper.setToUser(userId, EVENT_COLLECTION, null);
|
||||
}
|
||||
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user