1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 08:43:33 +00:00

[PM-5559] Implement User Notification Settings state provider (#8032)

* create user notification settings state provider

* replace state service get/set disableAddLoginNotification and disableChangedPasswordNotification with user notification settings service equivalents

* migrate disableAddLoginNotification and disableChangedPasswordNotification global settings to user notification settings state provider

* add content script messaging the background for enableChangedPasswordPrompt setting

* Implementing feedback to provide on PR

* Implementing feedback to provide on PR

* PR suggestions cleanup

---------

Co-authored-by: Cesar Gonzalez <cgonzalez@bitwarden.com>
This commit is contained in:
Jonathan Prusik
2024-03-04 14:12:23 -05:00
committed by GitHub
parent d87a8f9271
commit 4ba2717eb4
18 changed files with 409 additions and 138 deletions

View File

@@ -23,6 +23,7 @@ import { ClearClipboardDelayMigrator } from "./migrations/25-move-clear-clipboar
import { RevertLastSyncMigrator } from "./migrations/26-revert-move-last-sync-to-state-provider";
import { BadgeSettingsMigrator } from "./migrations/27-move-badge-settings-to-state-providers";
import { MoveBiometricUnlockToStateProviders } from "./migrations/28-move-biometric-unlock-to-state-providers";
import { UserNotificationSettingsKeyMigrator } from "./migrations/29-move-user-notification-settings-to-state-provider";
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";
@@ -33,7 +34,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
import { MinVersionMigrator } from "./migrations/min-version";
export const MIN_VERSION = 2;
export const CURRENT_VERSION = 28;
export const CURRENT_VERSION = 29;
export type MinVersion = typeof MIN_VERSION;
export function createMigrationBuilder() {
@@ -64,7 +65,8 @@ export function createMigrationBuilder() {
.with(ClearClipboardDelayMigrator, 24, 25)
.with(RevertLastSyncMigrator, 25, 26)
.with(BadgeSettingsMigrator, 26, 27)
.with(MoveBiometricUnlockToStateProviders, 27, CURRENT_VERSION);
.with(MoveBiometricUnlockToStateProviders, 27, 28)
.with(UserNotificationSettingsKeyMigrator, 28, CURRENT_VERSION);
}
export async function currentVersion(

View File

@@ -0,0 +1,102 @@
import { MockProxy } from "jest-mock-extended";
import { StateDefinitionLike, MigrationHelper } from "../migration-helper";
import { mockMigrationHelper } from "../migration-helper.spec";
import { UserNotificationSettingsKeyMigrator } from "./29-move-user-notification-settings-to-state-provider";
function exampleJSON() {
return {
global: {
disableAddLoginNotification: false,
disableChangedPasswordNotification: false,
otherStuff: "otherStuff1",
},
};
}
function rollbackJSON() {
return {
global_userNotificationSettings_enableAddedLoginPrompt: true,
global_userNotificationSettings_enableChangedPasswordPrompt: true,
global: {
otherStuff: "otherStuff1",
},
};
}
const userNotificationSettingsLocalStateDefinition: {
stateDefinition: StateDefinitionLike;
} = {
stateDefinition: {
name: "userNotificationSettings",
},
};
describe("ProviderKeysMigrator", () => {
let helper: MockProxy<MigrationHelper>;
let sut: UserNotificationSettingsKeyMigrator;
describe("migrate", () => {
beforeEach(() => {
helper = mockMigrationHelper(exampleJSON(), 28);
sut = new UserNotificationSettingsKeyMigrator(28, 29);
});
it("should remove disableAddLoginNotification and disableChangedPasswordNotification global setting", async () => {
await sut.migrate(helper);
expect(helper.set).toHaveBeenCalledTimes(2);
expect(helper.set).toHaveBeenCalledWith("global", { otherStuff: "otherStuff1" });
expect(helper.set).toHaveBeenCalledWith("global", { otherStuff: "otherStuff1" });
});
it("should set global user notification setting values", async () => {
await sut.migrate(helper);
expect(helper.setToGlobal).toHaveBeenCalledTimes(2);
expect(helper.setToGlobal).toHaveBeenCalledWith(
{ ...userNotificationSettingsLocalStateDefinition, key: "enableAddedLoginPrompt" },
true,
);
expect(helper.setToGlobal).toHaveBeenCalledWith(
{ ...userNotificationSettingsLocalStateDefinition, key: "enableChangedPasswordPrompt" },
true,
);
});
});
describe("rollback", () => {
beforeEach(() => {
helper = mockMigrationHelper(rollbackJSON(), 29);
sut = new UserNotificationSettingsKeyMigrator(28, 29);
});
it("should null out new global values", async () => {
await sut.rollback(helper);
expect(helper.setToGlobal).toHaveBeenCalledTimes(2);
expect(helper.setToGlobal).toHaveBeenCalledWith(
{ ...userNotificationSettingsLocalStateDefinition, key: "enableAddedLoginPrompt" },
null,
);
expect(helper.setToGlobal).toHaveBeenCalledWith(
{ ...userNotificationSettingsLocalStateDefinition, key: "enableChangedPasswordPrompt" },
null,
);
});
it("should add explicit global values back", async () => {
await sut.rollback(helper);
expect(helper.set).toHaveBeenCalledTimes(2);
expect(helper.set).toHaveBeenCalledWith("global", {
disableAddLoginNotification: false,
otherStuff: "otherStuff1",
});
expect(helper.set).toHaveBeenCalledWith("global", {
disableChangedPasswordNotification: false,
otherStuff: "otherStuff1",
});
});
});
});

View File

@@ -0,0 +1,105 @@
import { MigrationHelper } from "../migration-helper";
import { Migrator } from "../migrator";
type ExpectedGlobalState = {
disableAddLoginNotification?: boolean;
disableChangedPasswordNotification?: boolean;
};
export class UserNotificationSettingsKeyMigrator extends Migrator<28, 29> {
async migrate(helper: MigrationHelper): Promise<void> {
const globalState = await helper.get<ExpectedGlobalState>("global");
// disableAddLoginNotification -> enableAddedLoginPrompt
if (globalState?.disableAddLoginNotification != null) {
await helper.setToGlobal(
{
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableAddedLoginPrompt",
},
!globalState.disableAddLoginNotification,
);
// delete `disableAddLoginNotification` from state global
delete globalState.disableAddLoginNotification;
await helper.set<ExpectedGlobalState>("global", globalState);
}
// disableChangedPasswordNotification -> enableChangedPasswordPrompt
if (globalState?.disableChangedPasswordNotification != null) {
await helper.setToGlobal(
{
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableChangedPasswordPrompt",
},
!globalState.disableChangedPasswordNotification,
);
// delete `disableChangedPasswordNotification` from state global
delete globalState.disableChangedPasswordNotification;
await helper.set<ExpectedGlobalState>("global", globalState);
}
}
async rollback(helper: MigrationHelper): Promise<void> {
const globalState = (await helper.get<ExpectedGlobalState>("global")) || {};
const enableAddedLoginPrompt: boolean = await helper.getFromGlobal({
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableAddedLoginPrompt",
});
const enableChangedPasswordPrompt: boolean = await helper.getFromGlobal({
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableChangedPasswordPrompt",
});
// enableAddedLoginPrompt -> disableAddLoginNotification
if (enableAddedLoginPrompt) {
await helper.set<ExpectedGlobalState>("global", {
...globalState,
disableAddLoginNotification: !enableAddedLoginPrompt,
});
// remove the global state provider framework key for `enableAddedLoginPrompt`
await helper.setToGlobal(
{
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableAddedLoginPrompt",
},
null,
);
}
// enableChangedPasswordPrompt -> disableChangedPasswordNotification
if (enableChangedPasswordPrompt) {
await helper.set<ExpectedGlobalState>("global", {
...globalState,
disableChangedPasswordNotification: !enableChangedPasswordPrompt,
});
// remove the global state provider framework key for `enableChangedPasswordPrompt`
await helper.setToGlobal(
{
stateDefinition: {
name: "userNotificationSettings",
},
key: "enableChangedPasswordPrompt",
},
null,
);
}
}
}