1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-04 17:43:39 +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

@@ -109,6 +109,8 @@ type NotificationBackgroundExtensionMessageHandlers = {
bgReopenUnlockPopout: ({ sender }: BackgroundSenderParam) => Promise<void>;
checkNotificationQueue: ({ sender }: BackgroundSenderParam) => Promise<void>;
collectPageDetailsResponse: ({ message }: BackgroundMessageParam) => Promise<void>;
bgGetEnableChangedPasswordPrompt: () => Promise<boolean>;
bgGetEnableAddedLoginPrompt: () => Promise<boolean>;
getWebVaultUrlForNotification: () => string;
};

View File

@@ -4,6 +4,7 @@ import { firstValueFrom } from "rxjs";
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
@@ -45,6 +46,7 @@ describe("NotificationBackground", () => {
const policyService = mock<PolicyService>();
const folderService = mock<FolderService>();
const stateService = mock<BrowserStateService>();
const userNotificationSettingsService = mock<UserNotificationSettingsService>();
const environmentService = mock<EnvironmentService>();
const logService = mock<LogService>();
@@ -56,6 +58,7 @@ describe("NotificationBackground", () => {
policyService,
folderService,
stateService,
userNotificationSettingsService,
environmentService,
logService,
);
@@ -235,8 +238,8 @@ describe("NotificationBackground", () => {
let tab: chrome.tabs.Tab;
let sender: chrome.runtime.MessageSender;
let getAuthStatusSpy: jest.SpyInstance;
let getDisableAddLoginNotificationSpy: jest.SpyInstance;
let getDisableChangedPasswordNotificationSpy: jest.SpyInstance;
let getEnableAddedLoginPromptSpy: jest.SpyInstance;
let getEnableChangedPasswordPromptSpy: jest.SpyInstance;
let pushAddLoginToQueueSpy: jest.SpyInstance;
let pushChangePasswordToQueueSpy: jest.SpyInstance;
let getAllDecryptedForUrlSpy: jest.SpyInstance;
@@ -245,13 +248,13 @@ describe("NotificationBackground", () => {
tab = createChromeTabMock();
sender = mock<chrome.runtime.MessageSender>({ tab });
getAuthStatusSpy = jest.spyOn(authService, "getAuthStatus");
getDisableAddLoginNotificationSpy = jest.spyOn(
stateService,
"getDisableAddLoginNotification",
getEnableAddedLoginPromptSpy = jest.spyOn(
notificationBackground as any,
"getEnableAddedLoginPrompt",
);
getDisableChangedPasswordNotificationSpy = jest.spyOn(
stateService,
"getDisableChangedPasswordNotification",
getEnableChangedPasswordPromptSpy = jest.spyOn(
notificationBackground as any,
"getEnableChangedPasswordPrompt",
);
pushAddLoginToQueueSpy = jest.spyOn(notificationBackground as any, "pushAddLoginToQueue");
pushChangePasswordToQueueSpy = jest.spyOn(
@@ -272,7 +275,7 @@ describe("NotificationBackground", () => {
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).not.toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).not.toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
});
@@ -287,7 +290,7 @@ describe("NotificationBackground", () => {
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).not.toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).not.toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
});
@@ -297,13 +300,13 @@ describe("NotificationBackground", () => {
login: { username: "test", password: "password", url: "https://example.com" },
};
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Locked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(true);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(false);
sendExtensionRuntimeMessage(message, sender);
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled();
expect(getAllDecryptedForUrlSpy).not.toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled();
@@ -315,14 +318,14 @@ describe("NotificationBackground", () => {
login: { username: "test", password: "password", url: "https://example.com" },
};
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Unlocked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(true);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(false);
getAllDecryptedForUrlSpy.mockResolvedValueOnce([]);
sendExtensionRuntimeMessage(message, sender);
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled();
expect(getAllDecryptedForUrlSpy).toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled();
@@ -334,8 +337,8 @@ describe("NotificationBackground", () => {
login: { username: "test", password: "password", url: "https://example.com" },
};
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Unlocked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(false);
getDisableChangedPasswordNotificationSpy.mockReturnValueOnce(true);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(true);
getEnableChangedPasswordPromptSpy.mockReturnValueOnce(false);
getAllDecryptedForUrlSpy.mockResolvedValueOnce([
mock<CipherView>({ login: { username: "test", password: "oldPassword" } }),
]);
@@ -344,9 +347,9 @@ describe("NotificationBackground", () => {
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled();
expect(getAllDecryptedForUrlSpy).toHaveBeenCalled();
expect(getDisableChangedPasswordNotificationSpy).toHaveBeenCalled();
expect(getEnableChangedPasswordPromptSpy).toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled();
});
@@ -357,7 +360,7 @@ describe("NotificationBackground", () => {
login: { username: "test", password: "password", url: "https://example.com" },
};
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Unlocked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(false);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(true);
getAllDecryptedForUrlSpy.mockResolvedValueOnce([
mock<CipherView>({ login: { username: "test", password: "password" } }),
]);
@@ -366,7 +369,7 @@ describe("NotificationBackground", () => {
await flushPromises();
expect(getAuthStatusSpy).toHaveBeenCalled();
expect(getDisableAddLoginNotificationSpy).toHaveBeenCalled();
expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled();
expect(getAllDecryptedForUrlSpy).toHaveBeenCalled();
expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled();
expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled();
@@ -376,7 +379,7 @@ describe("NotificationBackground", () => {
const login = { username: "test", password: "password", url: "https://example.com" };
const message: NotificationBackgroundExtensionMessage = { command: "bgAddLogin", login };
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Locked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(false);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(true);
sendExtensionRuntimeMessage(message, sender);
await flushPromises();
@@ -393,7 +396,7 @@ describe("NotificationBackground", () => {
} as any;
const message: NotificationBackgroundExtensionMessage = { command: "bgAddLogin", login };
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Unlocked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(false);
getEnableAddedLoginPromptSpy.mockReturnValueOnce(true);
getAllDecryptedForUrlSpy.mockResolvedValueOnce([
mock<CipherView>({ login: { username: "anotherTestUsername", password: "password" } }),
]);
@@ -409,7 +412,8 @@ describe("NotificationBackground", () => {
const login = { username: "tEsT", password: "password", url: "https://example.com" };
const message: NotificationBackgroundExtensionMessage = { command: "bgAddLogin", login };
getAuthStatusSpy.mockResolvedValueOnce(AuthenticationStatus.Unlocked);
getDisableAddLoginNotificationSpy.mockReturnValueOnce(false);
getEnableAddedLoginPromptSpy.mockResolvedValueOnce(true);
getEnableChangedPasswordPromptSpy.mockResolvedValueOnce(true);
getAllDecryptedForUrlSpy.mockResolvedValueOnce([
mock<CipherView>({
id: "cipher-id",

View File

@@ -4,6 +4,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@@ -57,6 +58,8 @@ export default class NotificationBackground {
bgUnlockPopoutOpened: ({ message, sender }) => this.unlockVault(message, sender.tab),
checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab),
bgReopenUnlockPopout: ({ sender }) => this.openUnlockPopout(sender.tab),
bgGetEnableChangedPasswordPrompt: () => this.getEnableChangedPasswordPrompt(),
bgGetEnableAddedLoginPrompt: () => this.getEnableAddedLoginPrompt(),
getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
};
@@ -67,6 +70,7 @@ export default class NotificationBackground {
private policyService: PolicyService,
private folderService: FolderService,
private stateService: BrowserStateService,
private userNotificationSettingsService: UserNotificationSettingsServiceAbstraction,
private environmentService: EnvironmentService,
private logService: LogService,
) {}
@@ -81,6 +85,20 @@ export default class NotificationBackground {
this.cleanupNotificationQueue();
}
/**
* Gets the enableChangedPasswordPrompt setting from the user notification settings service.
*/
async getEnableChangedPasswordPrompt(): Promise<boolean> {
return await firstValueFrom(this.userNotificationSettingsService.enableChangedPasswordPrompt$);
}
/**
* Gets the enableAddedLoginPrompt setting from the user notification settings service.
*/
async getEnableAddedLoginPrompt(): Promise<boolean> {
return await firstValueFrom(this.userNotificationSettingsService.enableAddedLoginPrompt$);
}
/**
* Checks the notification queue for any messages that need to be sent to the
* specified tab. If no tab is specified, the current tab will be used.
@@ -194,9 +212,10 @@ export default class NotificationBackground {
return;
}
const disabledAddLogin = await this.stateService.getDisableAddLoginNotification();
const addLoginIsEnabled = await this.getEnableAddedLoginPrompt();
if (authStatus === AuthenticationStatus.Locked) {
if (!disabledAddLogin) {
if (addLoginIsEnabled) {
await this.pushAddLoginToQueue(loginDomain, loginInfo, sender.tab, true);
}
@@ -207,14 +226,15 @@ export default class NotificationBackground {
const usernameMatches = ciphers.filter(
(c) => c.login.username != null && c.login.username.toLowerCase() === normalizedUsername,
);
if (!disabledAddLogin && usernameMatches.length === 0) {
if (addLoginIsEnabled && usernameMatches.length === 0) {
await this.pushAddLoginToQueue(loginDomain, loginInfo, sender.tab);
return;
}
const disabledChangePassword = await this.stateService.getDisableChangedPasswordNotification();
const changePasswordIsEnabled = await this.getEnableChangedPasswordPrompt();
if (
!disabledChangePassword &&
changePasswordIsEnabled &&
usernameMatches.length === 1 &&
usernameMatches[0].login.password !== loginInfo.password
) {

View File

@@ -0,0 +1,25 @@
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import {
CachedServices,
factory,
FactoryOptions,
} from "../../../platform/background/service-factories/factory-options";
import {
stateProviderFactory,
StateProviderInitOptions,
} from "../../../platform/background/service-factories/state-provider.factory";
export type UserNotificationSettingsServiceInitOptions = FactoryOptions & StateProviderInitOptions;
export function userNotificationSettingsServiceFactory(
cache: { userNotificationSettingsService?: UserNotificationSettingsService } & CachedServices,
opts: UserNotificationSettingsServiceInitOptions,
): Promise<UserNotificationSettingsService> {
return factory(
cache,
"userNotificationSettingsService",
opts,
async () => new UserNotificationSettingsService(await stateProviderFactory(cache, opts)),
);
}

View File

@@ -7,7 +7,11 @@ import { WatchedForm } from "../models/watched-form";
import { NotificationBarIframeInitData } from "../notification/abstractions/notification-bar";
import { FormData } from "../services/abstractions/autofill.service";
import { GlobalSettings, UserSettings } from "../types";
import { getFromLocalStorage, setupExtensionDisconnectAction } from "../utils";
import {
getFromLocalStorage,
sendExtensionMessage,
setupExtensionDisconnectAction,
} from "../utils";
interface HTMLElementWithFormOpId extends HTMLElement {
formOpId: string;
@@ -86,12 +90,11 @@ async function loadNotificationBar() {
]);
const changePasswordButtonContainsNames = new Set(["pass", "change", "contras", "senha"]);
// These are preferences for whether to show the notification bar based on the user's settings
// and they are set in the Settings > Options page in the browser extension.
let disabledAddLoginNotification = false;
let disabledChangedPasswordNotification = false;
const enableChangedPasswordPrompt = await sendExtensionMessage(
"bgGetEnableChangedPasswordPrompt",
);
const enableAddedLoginPrompt = await sendExtensionMessage("bgGetEnableAddedLoginPrompt");
let showNotificationBar = true;
// Look up the active user id from storage
const activeUserIdKey = "activeUserId";
const globalStorageKey = "global";
@@ -121,11 +124,7 @@ async function loadNotificationBar() {
// Example: '{"bitwarden.com":null}'
const excludedDomainsDict = globalSettings.neverDomains;
if (!excludedDomainsDict || !(window.location.hostname in excludedDomainsDict)) {
// Set local disabled preferences
disabledAddLoginNotification = globalSettings.disableAddLoginNotification;
disabledChangedPasswordNotification = globalSettings.disableChangedPasswordNotification;
if (!disabledAddLoginNotification || !disabledChangedPasswordNotification) {
if (enableAddedLoginPrompt || enableChangedPasswordPrompt) {
// If the user has not disabled both notifications, then handle the initial page change (null -> actual page)
handlePageChange();
}
@@ -352,9 +351,7 @@ async function loadNotificationBar() {
// to avoid missing any forms that are added after the page loads
observeDom();
sendPlatformMessage({
command: "checkNotificationQueue",
});
void sendExtensionMessage("checkNotificationQueue");
}
// This is a safeguard in case the observer misses a SPA page change.
@@ -392,10 +389,7 @@ async function loadNotificationBar() {
*
* */
function collectPageDetails() {
sendPlatformMessage({
command: "bgCollectPageDetails",
sender: "notificationBar",
});
void sendExtensionMessage("bgCollectPageDetails", { sender: "notificationBar" });
}
// End Page Detail Collection Methods
@@ -620,10 +614,9 @@ async function loadNotificationBar() {
continue;
}
const disabledBoth = disabledChangedPasswordNotification && disabledAddLoginNotification;
// if user has not disabled both notifications and we have a username and password field,
// if user has enabled either add login or change password notification, and we have a username and password field
if (
!disabledBoth &&
(enableChangedPasswordPrompt || enableAddedLoginPrompt) &&
watchedForms[i].usernameEl != null &&
watchedForms[i].passwordEl != null
) {
@@ -639,10 +632,7 @@ async function loadNotificationBar() {
const passwordPopulated = login.password != null && login.password !== "";
if (userNamePopulated && passwordPopulated) {
processedForm(form);
sendPlatformMessage({
command: "bgAddLogin",
login,
});
void sendExtensionMessage("bgAddLogin", { login });
break;
} else if (
userNamePopulated &&
@@ -659,7 +649,7 @@ async function loadNotificationBar() {
// if user has not disabled the password changed notification and we have multiple password fields,
// then check if the user has changed their password
if (!disabledChangedPasswordNotification && watchedForms[i].passwordEls != null) {
if (enableChangedPasswordPrompt && watchedForms[i].passwordEls != null) {
// Get the values of the password fields
const passwords: string[] = watchedForms[i].passwordEls
.filter((el: HTMLInputElement) => el.value != null && el.value !== "")
@@ -716,7 +706,7 @@ async function loadNotificationBar() {
currentPassword: curPass,
url: document.URL,
};
sendPlatformMessage({ command: "bgChangedPassword", data });
void sendExtensionMessage("bgChangedPassword", { data });
break;
}
}
@@ -954,9 +944,7 @@ async function loadNotificationBar() {
switch (barType) {
case "add":
case "change":
sendPlatformMessage({
command: "bgRemoveTabFromNotificationQueue",
});
void sendExtensionMessage("bgRemoveTabFromNotificationQueue");
break;
default:
break;
@@ -981,12 +969,6 @@ async function loadNotificationBar() {
// End Notification Bar Functions (open, close, height adjustment, etc.)
// Helper Functions
function sendPlatformMessage(msg: any) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
chrome.runtime.sendMessage(msg);
}
function isInIframe() {
try {
return window.self !== window.top;

View File

@@ -166,11 +166,10 @@ describe("AutofillService", () => {
jest
.spyOn(autofillService, "getOverlayVisibility")
.mockResolvedValue(AutofillOverlayVisibility.OnFieldFocus);
jest.spyOn(autofillService, "getAutofillOnPageLoad").mockResolvedValue(true);
});
it("accepts an extension message sender and injects the autofill scripts into the tab of the sender", async () => {
jest.spyOn(autofillService, "getAutofillOnPageLoad").mockResolvedValue(true);
await autofillService.injectAutofillScripts(sender.tab, sender.frameId, true);
[autofillOverlayBootstrapScript, ...defaultAutofillScripts].forEach((scriptName) => {
@@ -195,11 +194,6 @@ describe("AutofillService", () => {
});
it("will inject the bootstrap-autofill-overlay script if the user has the autofill overlay enabled", async () => {
jest
.spyOn(autofillService, "getOverlayVisibility")
.mockResolvedValue(AutofillOverlayVisibility.OnFieldFocus);
jest.spyOn(autofillService, "getAutofillOnPageLoad").mockResolvedValue(true);
await autofillService.injectAutofillScripts(sender.tab, sender.frameId);
expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(tabMock.id, {
@@ -218,7 +212,6 @@ describe("AutofillService", () => {
jest
.spyOn(autofillService, "getOverlayVisibility")
.mockResolvedValue(AutofillOverlayVisibility.Off);
jest.spyOn(autofillService, "getAutofillOnPageLoad").mockResolvedValue(true);
await autofillService.injectAutofillScripts(sender.tab, sender.frameId);
@@ -235,8 +228,6 @@ describe("AutofillService", () => {
});
it("injects the content-message-handler script if not injecting on page load", async () => {
jest.spyOn(autofillService, "getAutofillOnPageLoad").mockResolvedValue(true);
await autofillService.injectAutofillScripts(sender.tab, sender.frameId, false);
expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(tabMock.id, {

View File

@@ -39,10 +39,7 @@ export type UserSettings = {
vaultTimeoutAction: VaultTimeoutAction;
};
export type GlobalSettings = Pick<
GlobalState,
"disableAddLoginNotification" | "disableChangedPasswordNotification" | "neverDomains"
>;
export type GlobalSettings = Pick<GlobalState, "neverDomains">;
/**
* A HTMLElement (usually a form element) with additional custom properties added by this script

View File

@@ -55,6 +55,10 @@ import {
BadgeSettingsServiceAbstraction,
BadgeSettingsService,
} from "@bitwarden/common/autofill/services/badge-settings.service";
import {
UserNotificationSettingsService,
UserNotificationSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
@@ -248,6 +252,7 @@ export default class MainBackground {
searchService: SearchServiceAbstraction;
notificationsService: NotificationsServiceAbstraction;
stateService: StateServiceAbstraction;
userNotificationSettingsService: UserNotificationSettingsServiceAbstraction;
autofillSettingsService: AutofillSettingsServiceAbstraction;
badgeSettingsService: BadgeSettingsServiceAbstraction;
systemService: SystemServiceAbstraction;
@@ -419,6 +424,7 @@ export default class MainBackground {
this.environmentService,
migrationRunner,
);
this.userNotificationSettingsService = new UserNotificationSettingsService(this.stateProvider);
this.platformUtilsService = new BrowserPlatformUtilsService(
this.messagingService,
(clipboardValue, clearMs) => {
@@ -846,6 +852,7 @@ export default class MainBackground {
this.policyService,
this.folderService,
this.stateService,
this.userNotificationSettingsService,
this.environmentService,
this.logService,
);
@@ -1088,10 +1095,12 @@ export default class MainBackground {
this.keyConnectorService.clear(),
this.vaultFilterService.clear(),
this.biometricStateService.logout(userId),
/* We intentionally do not clear:
* - autofillSettingsService
* - badgeSettingsService
*/
/*
We intentionally do not clear:
- autofillSettingsService
- badgeSettingsService
- userNotificationSettingsService
*/
]);
//Needs to be checked before state is cleaned

View File

@@ -42,6 +42,10 @@ import {
AutofillSettingsService,
AutofillSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/autofill-settings.service";
import {
UserNotificationSettingsService,
UserNotificationSettingsServiceAbstraction,
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
@@ -551,6 +555,11 @@ function getBgService<T>(service: keyof MainBackground) {
useClass: AutofillSettingsService,
deps: [StateProvider, PolicyService],
},
{
provide: UserNotificationSettingsServiceAbstraction,
useClass: UserNotificationSettingsService,
deps: [StateProvider],
},
],
})
export class ServicesModule {}

View File

@@ -5,6 +5,7 @@ import { AbstractThemingService } from "@bitwarden/angular/platform/services/the
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service";
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
@@ -47,6 +48,7 @@ export class OptionsComponent implements OnInit {
constructor(
private messagingService: MessagingService,
private stateService: StateService,
private userNotificationSettingsService: UserNotificationSettingsServiceAbstraction,
private autofillSettingsService: AutofillSettingsServiceAbstraction,
private badgeSettingsService: BadgeSettingsServiceAbstraction,
i18nService: I18nService,
@@ -95,10 +97,13 @@ export class OptionsComponent implements OnInit {
this.autofillSettingsService.autofillOnPageLoadDefault$,
);
this.enableAddLoginNotification = !(await this.stateService.getDisableAddLoginNotification());
this.enableAddLoginNotification = await firstValueFrom(
this.userNotificationSettingsService.enableAddedLoginPrompt$,
);
this.enableChangedPasswordNotification =
!(await this.stateService.getDisableChangedPasswordNotification());
this.enableChangedPasswordNotification = await firstValueFrom(
this.userNotificationSettingsService.enableChangedPasswordPrompt$,
);
this.enableContextMenuItem = !(await this.stateService.getDisableContextMenuItem());
@@ -122,12 +127,14 @@ export class OptionsComponent implements OnInit {
}
async updateAddLoginNotification() {
await this.stateService.setDisableAddLoginNotification(!this.enableAddLoginNotification);
await this.userNotificationSettingsService.setEnableAddedLoginPrompt(
this.enableAddLoginNotification,
);
}
async updateChangedPasswordNotification() {
await this.stateService.setDisableChangedPasswordNotification(
!this.enableChangedPasswordNotification,
await this.userNotificationSettingsService.setEnableChangedPasswordPrompt(
this.enableChangedPasswordNotification,
);
}