1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 13:53:34 +00:00

PM-25075 [Remove - Step 1] Flagged logic from clients/server and clients notification-refresh feature flag (#16113)

* PM-25075 wip parking work

* remove flag from enums and add fade out

* fix tests

* remove flags from enum file after merge conflict re introduced

* remove dead code paths

* change naming back to bgUnlockPopoutOpened
This commit is contained in:
Daniel Riera
2025-09-15 14:55:36 -04:00
committed by GitHub
parent 4449cf45d8
commit 7ce8d06315
13 changed files with 159 additions and 616 deletions

View File

@@ -43,17 +43,13 @@ describe("AuthPopoutWindow", () => {
singleActionKey: AuthPopoutType.unlockExtension, singleActionKey: AuthPopoutType.unlockExtension,
senderWindowId: 1, senderWindowId: 1,
}); });
expect(sendMessageDataSpy).toHaveBeenCalledWith(senderTab, "bgUnlockPopoutOpened", { expect(sendMessageDataSpy).toHaveBeenCalledWith(senderTab, "bgUnlockPopoutOpened", {});
skipNotification: false,
});
}); });
it("sends an indication that the presenting the notification bar for unlocking the extension should be skipped", async () => { it("sends the bgUnlockPopoutOpened message", async () => {
await openUnlockPopout(senderTab, true); await openUnlockPopout(senderTab);
expect(sendMessageDataSpy).toHaveBeenCalledWith(senderTab, "bgUnlockPopoutOpened", { expect(sendMessageDataSpy).toHaveBeenCalledWith(senderTab, "bgUnlockPopoutOpened", {});
skipNotification: true,
});
}); });
it("closes any existing popup window types that are open to the unlock extension route", async () => { it("closes any existing popup window types that are open to the unlock extension route", async () => {

View File

@@ -20,9 +20,8 @@ const extensionUnlockUrls = new Set([
* Opens a window that facilitates unlocking / logging into the extension. * Opens a window that facilitates unlocking / logging into the extension.
* *
* @param senderTab - Used to determine the windowId of the sender. * @param senderTab - Used to determine the windowId of the sender.
* @param skipNotification - Used to determine whether to show the unlock notification.
*/ */
async function openUnlockPopout(senderTab: chrome.tabs.Tab, skipNotification = false) { async function openUnlockPopout(senderTab: chrome.tabs.Tab) {
const existingPopoutWindowTabs = await BrowserApi.tabsQuery({ windowType: "popup" }); const existingPopoutWindowTabs = await BrowserApi.tabsQuery({ windowType: "popup" });
existingPopoutWindowTabs.forEach((tab) => { existingPopoutWindowTabs.forEach((tab) => {
if (extensionUnlockUrls.has(tab.url)) { if (extensionUnlockUrls.has(tab.url)) {
@@ -36,7 +35,7 @@ async function openUnlockPopout(senderTab: chrome.tabs.Tab, skipNotification = f
singleActionKey: AuthPopoutType.unlockExtension, singleActionKey: AuthPopoutType.unlockExtension,
senderWindowId: senderTab.windowId, senderWindowId: senderTab.windowId,
}); });
await BrowserApi.tabSendMessageData(senderTab, "bgUnlockPopoutOpened", { skipNotification }); await BrowserApi.tabSendMessageData(senderTab, "bgUnlockPopoutOpened", {});
} }
/** /**

View File

@@ -141,7 +141,6 @@ type NotificationBackgroundExtensionMessageHandlers = {
sender, sender,
}: BackgroundOnMessageHandlerParams) => Promise<void>; }: BackgroundOnMessageHandlerParams) => Promise<void>;
bgNeverSave: ({ sender }: BackgroundSenderParam) => Promise<void>; bgNeverSave: ({ sender }: BackgroundSenderParam) => Promise<void>;
bgUnlockPopoutOpened: ({ message, sender }: BackgroundOnMessageHandlerParams) => Promise<void>;
bgReopenUnlockPopout: ({ sender }: BackgroundSenderParam) => Promise<void>; bgReopenUnlockPopout: ({ sender }: BackgroundSenderParam) => Promise<void>;
checkNotificationQueue: ({ sender }: BackgroundSenderParam) => Promise<void>; checkNotificationQueue: ({ sender }: BackgroundSenderParam) => Promise<void>;
collectPageDetailsResponse: ({ message }: BackgroundMessageParam) => Promise<void>; collectPageDetailsResponse: ({ message }: BackgroundMessageParam) => Promise<void>;

View File

@@ -817,6 +817,7 @@ describe("NotificationBackground", () => {
reprompt: CipherRepromptType.None, reprompt: CipherRepromptType.None,
}); });
getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView);
taskService.tasksEnabled$.mockImplementation(() => of(false));
sendMockExtensionMessage(message, sender); sendMockExtensionMessage(message, sender);
await flushPromises(); await flushPromises();
@@ -865,7 +866,7 @@ describe("NotificationBackground", () => {
reprompt: CipherRepromptType.Password, reprompt: CipherRepromptType.Password,
}); });
getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView); getDecryptedCipherByIdSpy.mockResolvedValueOnce(cipherView);
taskService.tasksEnabled$.mockImplementation(() => of(false));
sendMockExtensionMessage(message, sender); sendMockExtensionMessage(message, sender);
await flushPromises(); await flushPromises();
@@ -913,9 +914,6 @@ describe("NotificationBackground", () => {
taskService.pendingTasks$.mockImplementation(() => taskService.pendingTasks$.mockImplementation(() =>
of([mockSecurityTask, mockSecurityTask2]), of([mockSecurityTask, mockSecurityTask2]),
); );
jest
.spyOn(notificationBackground as any, "getNotificationFlag")
.mockResolvedValueOnce(true);
jest.spyOn(notificationBackground as any, "getOrgData").mockResolvedValueOnce([ jest.spyOn(notificationBackground as any, "getOrgData").mockResolvedValueOnce([
{ {
id: mockOrgId, id: mockOrgId,
@@ -1372,74 +1370,6 @@ describe("NotificationBackground", () => {
}); });
}); });
describe("bgUnlockPopoutOpened message handler", () => {
let pushUnlockVaultToQueueSpy: jest.SpyInstance;
beforeEach(() => {
pushUnlockVaultToQueueSpy = jest.spyOn(
notificationBackground as any,
"pushUnlockVaultToQueue",
);
});
it("skips pushing the unlock vault message to the queue if the message indicates that the notification should be skipped", async () => {
const tabMock = createChromeTabMock();
const sender = mock<chrome.runtime.MessageSender>({ tab: tabMock });
const message: NotificationBackgroundExtensionMessage = {
command: "bgUnlockPopoutOpened",
data: { skipNotification: true },
};
sendMockExtensionMessage(message, sender);
await flushPromises();
expect(pushUnlockVaultToQueueSpy).not.toHaveBeenCalled();
});
it("skips pushing the unlock vault message to the queue if the auth status is not `Locked`", async () => {
const tabMock = createChromeTabMock();
const sender = mock<chrome.runtime.MessageSender>({ tab: tabMock });
const message: NotificationBackgroundExtensionMessage = {
command: "bgUnlockPopoutOpened",
};
activeAccountStatusMock$.next(AuthenticationStatus.LoggedOut);
sendMockExtensionMessage(message, sender);
await flushPromises();
expect(pushUnlockVaultToQueueSpy).not.toHaveBeenCalled();
});
it("skips pushing the unlock vault message to the queue if the notification queue already has an item", async () => {
const tabMock = createChromeTabMock();
const sender = mock<chrome.runtime.MessageSender>({ tab: tabMock });
const message: NotificationBackgroundExtensionMessage = {
command: "bgUnlockPopoutOpened",
};
activeAccountStatusMock$.next(AuthenticationStatus.Locked);
notificationBackground["notificationQueue"] = [mock<AddLoginQueueMessage>()];
sendMockExtensionMessage(message, sender);
await flushPromises();
expect(pushUnlockVaultToQueueSpy).not.toHaveBeenCalled();
});
it("sends an unlock vault message to the queue if the user has a locked vault", async () => {
const tabMock = createChromeTabMock({ url: "https://example.com" });
const sender = mock<chrome.runtime.MessageSender>({ tab: tabMock });
const message: NotificationBackgroundExtensionMessage = {
command: "bgUnlockPopoutOpened",
};
activeAccountStatusMock$.next(AuthenticationStatus.Locked);
sendMockExtensionMessage(message, sender);
await flushPromises();
expect(pushUnlockVaultToQueueSpy).toHaveBeenCalledWith("example.com", sender.tab);
});
});
describe("checkNotificationQueue", () => { describe("checkNotificationQueue", () => {
let doNotificationQueueCheckSpy: jest.SpyInstance; let doNotificationQueueCheckSpy: jest.SpyInstance;
let getTabFromCurrentWindowSpy: jest.SpyInstance; let getTabFromCurrentWindowSpy: jest.SpyInstance;

View File

@@ -22,7 +22,6 @@ import {
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service"; import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { ProductTierType } from "@bitwarden/common/billing/enums/product-tier-type.enum"; import { ProductTierType } from "@bitwarden/common/billing/enums/product-tier-type.enum";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service"; import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config"; import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
@@ -67,7 +66,6 @@ import { TemporaryNotificationChangeLoginService } from "../services/notificatio
import { import {
AddChangePasswordNotificationQueueMessage, AddChangePasswordNotificationQueueMessage,
AddLoginQueueMessage, AddLoginQueueMessage,
AddUnlockVaultQueueMessage,
AddLoginMessageData, AddLoginMessageData,
NotificationQueueMessageItem, NotificationQueueMessageItem,
LockedVaultPendingNotificationsData, LockedVaultPendingNotificationsData,
@@ -116,12 +114,10 @@ export default class NotificationBackground {
bgSaveCipher: ({ message, sender }) => this.handleSaveCipherMessage(message, sender), bgSaveCipher: ({ message, sender }) => this.handleSaveCipherMessage(message, sender),
bgHandleReprompt: ({ message, sender }: any) => bgHandleReprompt: ({ message, sender }: any) =>
this.handleCipherUpdateRepromptResponse(message), this.handleCipherUpdateRepromptResponse(message),
bgUnlockPopoutOpened: ({ message, sender }) => this.unlockVault(message, sender.tab),
checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab), checkNotificationQueue: ({ sender }) => this.checkNotificationQueue(sender.tab),
collectPageDetailsResponse: ({ message }) => collectPageDetailsResponse: ({ message }) =>
this.handleCollectPageDetailsResponseMessage(message), this.handleCollectPageDetailsResponseMessage(message),
getWebVaultUrlForNotification: () => this.getWebVaultUrl(), getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
notificationRefreshFlagValue: () => this.getNotificationFlag(),
unlockCompleted: ({ message, sender }) => this.handleUnlockCompleted(message, sender), unlockCompleted: ({ message, sender }) => this.handleUnlockCompleted(message, sender),
}; };
@@ -351,15 +347,6 @@ export default class NotificationBackground {
return await firstValueFrom(this.configService.serverConfig$); return await firstValueFrom(this.configService.serverConfig$);
} }
/**
* Gets the current value of the notification refresh feature flag
* @returns Promise<boolean> indicating if the feature is enabled
*/
async getNotificationFlag(): Promise<boolean> {
const flagValue = await this.configService.getFeatureFlag(FeatureFlag.NotificationRefresh);
return flagValue;
}
/** /**
* Gets the current authentication status of the user. * Gets the current authentication status of the user.
* @returns Promise<AuthenticationStatus> - The current authentication status of the user. * @returns Promise<AuthenticationStatus> - The current authentication status of the user.
@@ -465,11 +452,6 @@ export default class NotificationBackground {
data: ModifyLoginCipherFormData, data: ModifyLoginCipherFormData,
tab: chrome.tabs.Tab, tab: chrome.tabs.Tab,
): Promise<boolean> { ): Promise<boolean> {
const flag = await this.getNotificationFlag();
if (!flag) {
return false;
}
const activeUserId = await firstValueFrom( const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(getOptionalUserId), this.accountService.activeAccount$.pipe(getOptionalUserId),
); );
@@ -683,34 +665,6 @@ export default class NotificationBackground {
}); });
} }
/**
* Sets up a notification to unlock the vault when the user
* attempts to autofill a cipher while the vault is locked.
*
* @param message - Extension message, determines if the notification should be skipped
* @param tab - The tab that the message was sent from
*/
private async unlockVault(message: NotificationBackgroundExtensionMessage, tab: chrome.tabs.Tab) {
const notificationRefreshFlagEnabled = await this.getNotificationFlag();
if (message.data?.skipNotification) {
return;
}
if (notificationRefreshFlagEnabled) {
return;
}
const currentAuthStatus = await this.getAuthStatus();
if (currentAuthStatus !== AuthenticationStatus.Locked || this.notificationQueue.length) {
return;
}
const loginDomain = Utils.getDomain(tab.url);
if (loginDomain) {
await this.pushUnlockVaultToQueue(loginDomain, tab);
}
}
private async pushChangePasswordToQueue( private async pushChangePasswordToQueue(
cipherId: string, cipherId: string,
loginDomain: string, loginDomain: string,
@@ -734,20 +688,6 @@ export default class NotificationBackground {
await this.checkNotificationQueue(tab); await this.checkNotificationQueue(tab);
} }
private async pushUnlockVaultToQueue(loginDomain: string, tab: chrome.tabs.Tab) {
this.removeTabFromNotificationQueue(tab);
const launchTimestamp = new Date().getTime();
const message: AddUnlockVaultQueueMessage = {
type: NotificationType.UnlockVault,
domain: loginDomain,
tab: tab,
launchTimestamp,
expires: new Date(launchTimestamp + 0.5 * 60000), // 30 seconds
wasVaultLocked: true,
};
await this.sendNotificationQueueMessage(tab, message);
}
/** /**
* Saves a cipher based on the message sent from the notification bar. If the vault * Saves a cipher based on the message sent from the notification bar. If the vault
* is locked, the message will be added to the notification queue and the unlock * is locked, the message will be added to the notification queue and the unlock
@@ -906,12 +846,11 @@ export default class NotificationBackground {
} }
const cipher = await this.cipherService.encrypt(cipherView, userId); const cipher = await this.cipherService.encrypt(cipherView, userId);
const shouldGetTasks = await this.getNotificationFlag();
try { try {
if (!cipherView.edit) { if (!cipherView.edit) {
throw new Error("You do not have permission to edit this cipher."); throw new Error("You do not have permission to edit this cipher.");
} }
const tasks = shouldGetTasks ? await this.getSecurityTasks(userId) : []; const tasks = await this.getSecurityTasks(userId);
const updatedCipherTask = tasks.find((task) => task.cipherId === cipherView?.id); const updatedCipherTask = tasks.find((task) => task.cipherId === cipherView?.id);
const cipherHasTask = !!updatedCipherTask?.id; const cipherHasTask = !!updatedCipherTask?.id;

View File

@@ -2107,7 +2107,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
"addToLockedVaultPendingNotifications", "addToLockedVaultPendingNotifications",
retryMessage, retryMessage,
); );
await this.openUnlockPopout(sender.tab, true); await this.openUnlockPopout(sender.tab);
} }
/** /**

View File

@@ -100,10 +100,19 @@ describe("ContentMessageHandler", () => {
}); });
it("forwards the message to the extension background if it is present in the forwardCommands list", () => { it("forwards the message to the extension background if it is present in the forwardCommands list", () => {
sendMockExtensionMessage({ command: "bgUnlockPopoutOpened" }); const forwardCommands = [
"addToLockedVaultPendingNotifications",
"unlockCompleted",
"addedCipher",
];
expect(sendMessageSpy).toHaveBeenCalledTimes(1); forwardCommands.forEach((command) => {
expect(sendMessageSpy).toHaveBeenCalledWith({ command: "bgUnlockPopoutOpened" }); sendMockExtensionMessage({ command });
expect(sendMessageSpy).toHaveBeenCalledWith({ command });
});
expect(sendMessageSpy).toHaveBeenCalledTimes(forwardCommands.length);
}); });
}); });

View File

@@ -1,10 +1,8 @@
import { render } from "lit"; import { render } from "lit";
import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums"; import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums";
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { AdjustNotificationBarMessageData } from "../background/abstractions/notification.background";
import { NotificationCipherData } from "../content/components/cipher/types"; import { NotificationCipherData } from "../content/components/cipher/types";
import { CollectionView, I18n, OrgView } from "../content/components/common-types"; import { CollectionView, I18n, OrgView } from "../content/components/common-types";
import { AtRiskNotification } from "../content/components/notification/at-risk-password/container"; import { AtRiskNotification } from "../content/components/notification/at-risk-password/container";
@@ -12,8 +10,6 @@ import { NotificationConfirmationContainer } from "../content/components/notific
import { NotificationContainer } from "../content/components/notification/container"; import { NotificationContainer } from "../content/components/notification/container";
import { selectedFolder as selectedFolderSignal } from "../content/components/signals/selected-folder"; import { selectedFolder as selectedFolderSignal } from "../content/components/signals/selected-folder";
import { selectedVault as selectedVaultSignal } from "../content/components/signals/selected-vault"; import { selectedVault as selectedVaultSignal } from "../content/components/signals/selected-vault";
import { buildSvgDomElement } from "../utils";
import { circleCheckIcon } from "../utils/svg-icons";
import { import {
NotificationBarWindowMessageHandlers, NotificationBarWindowMessageHandlers,
@@ -23,34 +19,18 @@ import {
NotificationTypes, NotificationTypes,
} from "./abstractions/notification-bar"; } from "./abstractions/notification-bar";
const logService = new ConsoleLogService(false);
let notificationBarIframeInitData: NotificationBarIframeInitData = {}; let notificationBarIframeInitData: NotificationBarIframeInitData = {};
let windowMessageOrigin: string; let windowMessageOrigin: string;
let useComponentBar = false;
const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers = { const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers = {
initNotificationBar: ({ message }) => initNotificationBar(message), initNotificationBar: ({ message }) => initNotificationBar(message),
saveCipherAttemptCompleted: ({ message }) => saveCipherAttemptCompleted: ({ message }) => handleSaveCipherConfirmation(message),
useComponentBar
? handleSaveCipherConfirmation(message)
: handleSaveCipherAttemptCompletedMessage(message),
}; };
globalThis.addEventListener("load", load); globalThis.addEventListener("load", load);
function load() { function load() {
setupWindowMessageListener(); setupWindowMessageListener();
sendPlatformMessage({ command: "notificationRefreshFlagValue" }, (flagValue) => {
useComponentBar = flagValue;
applyNotificationBarStyle();
});
}
function applyNotificationBarStyle() {
if (!useComponentBar) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("./bar.scss");
}
postMessageToParent({ command: "initNotificationBar" }); postMessageToParent({ command: "initNotificationBar" });
} }
@@ -99,25 +79,6 @@ function getI18n() {
}; };
} }
/**
* Attempts to locate an element by ID within a templates content and casts it to the specified type.
*
* @param templateElement - The template whose content will be searched for the element.
* @param elementId - The ID of the element being searched for.
* @returns The typed element if found, otherwise log error.
*
*/
const findElementById = <ElementType extends HTMLElement>(
templateElement: HTMLTemplateElement,
elementId: string,
): ElementType => {
const element = templateElement.content.getElementById(elementId);
if (!element) {
throw new Error(`Element with ID "${elementId}" not found in template.`);
}
return element as ElementType;
};
/** /**
* Returns the localized header message for the notification bar based on the notification type. * Returns the localized header message for the notification bar based on the notification type.
* *
@@ -204,25 +165,6 @@ export function getNotificationTestId(
}[notificationType]; }[notificationType];
} }
/**
* Sets the text content of an element identified by ID within a template's content.
*
* @param template - The template whose content will be searched for the element.
* @param elementId - The ID of the element whose text content is to be set.
* @param text - The text content to set for the specified element.
* @returns void
*
* This function attempts to locate an element by its ID within the content of a given HTML template.
* If the element is found, it updates the element's text content with the provided text.
* If the element is not found, the function does nothing, ensuring that the operation is safe and does not throw errors.
*/
function setElementText(template: HTMLTemplateElement, elementId: string, text: string): void {
const element = template.content.getElementById(elementId);
if (element) {
element.textContent = text;
}
}
async function initNotificationBar(message: NotificationBarWindowMessage) { async function initNotificationBar(message: NotificationBarWindowMessage) {
const { initData } = message; const { initData } = message;
if (!initData) { if (!initData) {
@@ -232,189 +174,119 @@ async function initNotificationBar(message: NotificationBarWindowMessage) {
notificationBarIframeInitData = initData; notificationBarIframeInitData = initData;
const { const {
isVaultLocked, isVaultLocked,
removeIndividualVault: personalVaultDisallowed, // renamed to avoid local method collision removeIndividualVault: personalVaultDisallowed,
theme, theme,
} = notificationBarIframeInitData; } = notificationBarIframeInitData;
const i18n = getI18n(); const i18n = getI18n();
const resolvedTheme = getResolvedTheme(theme ?? ThemeTypes.Light); const resolvedTheme = getResolvedTheme(theme ?? ThemeTypes.Light);
if (useComponentBar) { const resolvedType = resolveNotificationType(notificationBarIframeInitData);
const resolvedType = resolveNotificationType(notificationBarIframeInitData); const headerMessage = getNotificationHeaderMessage(i18n, resolvedType);
const headerMessage = getNotificationHeaderMessage(i18n, resolvedType); const notificationTestId = getNotificationTestId(resolvedType);
const notificationTestId = getNotificationTestId(resolvedType); appendHeaderMessageToTitle(headerMessage);
appendHeaderMessageToTitle(headerMessage);
document.body.innerHTML = ""; document.body.innerHTML = "";
// Current implementations utilize a require for scss files which creates the need to remove the node.
document.head.querySelectorAll('link[rel="stylesheet"]').forEach((node) => node.remove());
if (isVaultLocked) { if (isVaultLocked) {
const notificationConfig = { const notificationConfig = {
...notificationBarIframeInitData,
headerMessage,
type: resolvedType,
notificationTestId,
theme: resolvedTheme,
personalVaultIsAllowed: !personalVaultDisallowed,
handleCloseNotification,
handleEditOrUpdateAction,
i18n,
};
const handleSaveAction = () => {
sendSaveCipherMessage(true);
render(
NotificationContainer({
...notificationConfig,
handleSaveAction: () => {},
isLoading: true,
}),
document.body,
);
};
const UnlockNotification = NotificationContainer({ ...notificationConfig, handleSaveAction });
return render(UnlockNotification, document.body);
}
// Handle AtRiskPasswordNotification render
if (notificationBarIframeInitData.type === NotificationTypes.AtRiskPassword) {
return render(
AtRiskNotification({
...notificationBarIframeInitData,
type: notificationBarIframeInitData.type as NotificationType,
theme: resolvedTheme,
i18n,
notificationTestId,
params: initData.params,
handleCloseNotification,
}),
document.body,
);
}
// Default scenario: add or update password
const orgId = selectedVaultSignal.get();
await Promise.all([
new Promise<OrgView[]>((resolve) => sendPlatformMessage({ command: "bgGetOrgData" }, resolve)),
new Promise<FolderView[]>((resolve) =>
sendPlatformMessage({ command: "bgGetFolderData" }, resolve),
),
new Promise<NotificationCipherData[]>((resolve) =>
sendPlatformMessage({ command: "bgGetDecryptedCiphers" }, resolve),
),
new Promise<CollectionView[]>((resolve) =>
sendPlatformMessage({ command: "bgGetCollectionData", orgId }, resolve),
),
]).then(([organizations, folders, ciphers, collections]) => {
notificationBarIframeInitData = {
...notificationBarIframeInitData,
organizations,
folders,
ciphers,
collections,
};
// @TODO use context to avoid prop drilling
return render(
NotificationContainer({
...notificationBarIframeInitData, ...notificationBarIframeInitData,
headerMessage, headerMessage,
type: resolvedType, type: resolvedType,
notificationTestId,
theme: resolvedTheme, theme: resolvedTheme,
notificationTestId,
personalVaultIsAllowed: !personalVaultDisallowed, personalVaultIsAllowed: !personalVaultDisallowed,
handleCloseNotification, handleCloseNotification,
handleSaveAction,
handleEditOrUpdateAction, handleEditOrUpdateAction,
i18n, i18n,
}; }),
document.body,
);
});
const handleSaveAction = () => {
sendSaveCipherMessage(true);
render(
NotificationContainer({
...notificationConfig,
handleSaveAction: () => {},
isLoading: true,
}),
document.body,
);
};
const UnlockNotification = NotificationContainer({ ...notificationConfig, handleSaveAction });
return render(UnlockNotification, document.body);
}
// Handle AtRiskPasswordNotification render
if (notificationBarIframeInitData.type === NotificationTypes.AtRiskPassword) {
return render(
AtRiskNotification({
...notificationBarIframeInitData,
type: notificationBarIframeInitData.type as NotificationType,
theme: resolvedTheme,
i18n,
notificationTestId,
params: initData.params,
handleCloseNotification,
}),
document.body,
);
}
// Default scenario: add or update password
const orgId = selectedVaultSignal.get();
await Promise.all([
new Promise<OrgView[]>((resolve) =>
sendPlatformMessage({ command: "bgGetOrgData" }, resolve),
),
new Promise<FolderView[]>((resolve) =>
sendPlatformMessage({ command: "bgGetFolderData" }, resolve),
),
new Promise<NotificationCipherData[]>((resolve) =>
sendPlatformMessage({ command: "bgGetDecryptedCiphers" }, resolve),
),
new Promise<CollectionView[]>((resolve) =>
sendPlatformMessage({ command: "bgGetCollectionData", orgId }, resolve),
),
]).then(([organizations, folders, ciphers, collections]) => {
notificationBarIframeInitData = {
...notificationBarIframeInitData,
organizations,
folders,
ciphers,
collections,
};
// @TODO use context to avoid prop drilling
return render(
NotificationContainer({
...notificationBarIframeInitData,
headerMessage,
type: resolvedType,
theme: resolvedTheme,
notificationTestId,
personalVaultIsAllowed: !personalVaultDisallowed,
handleCloseNotification,
handleSaveAction,
handleEditOrUpdateAction,
i18n,
}),
document.body,
);
});
} else {
setNotificationBarTheme();
(document.getElementById("logo") as HTMLImageElement).src = isVaultLocked
? chrome.runtime.getURL("images/icon38_locked.png")
: chrome.runtime.getURL("images/icon38.png");
setupLogoLink(i18n.appName);
// i18n for "Add" template
const addTemplate = document.getElementById("template-add") as HTMLTemplateElement;
const neverButton = findElementById<HTMLButtonElement>(addTemplate, "never-save");
neverButton.textContent = i18n.never;
const selectFolder = findElementById<HTMLSelectElement>(addTemplate, "select-folder");
selectFolder.hidden = isVaultLocked || removeIndividualVault();
selectFolder.setAttribute("aria-label", i18n.folder);
const addButton = findElementById<HTMLButtonElement>(addTemplate, "add-save");
addButton.textContent = i18n.notificationAddSave;
const addEditButton = findElementById<HTMLButtonElement>(addTemplate, "add-edit");
// If Remove Individual Vault policy applies, "Add" opens the edit tab, so we hide the Edit button
addEditButton.hidden = removeIndividualVault();
addEditButton.textContent = i18n.notificationEdit;
setElementText(addTemplate, "add-text", i18n.notificationAddDesc);
// i18n for "Change" (update password) template
const changeTemplate = document.getElementById("template-change") as HTMLTemplateElement;
const changeButton = findElementById<HTMLSelectElement>(changeTemplate, "change-save");
changeButton.textContent = i18n.notificationUpdate;
const changeEditButton = findElementById<HTMLButtonElement>(changeTemplate, "change-edit");
changeEditButton.textContent = i18n.notificationEdit;
setElementText(changeTemplate, "change-text", i18n.notificationChangeDesc);
// i18n for "Unlock" (unlock extension) template
const unlockTemplate = document.getElementById("template-unlock") as HTMLTemplateElement;
const unlockButton = findElementById<HTMLButtonElement>(unlockTemplate, "unlock-vault");
unlockButton.textContent = i18n.notificationUnlock;
setElementText(unlockTemplate, "unlock-text", i18n.notificationUnlockDesc);
// i18n for body content
const closeButton = document.getElementById("close-button");
if (closeButton) {
closeButton.title = i18n.close;
}
const notificationType = initData.type;
if (notificationType === "add") {
handleTypeAdd();
} else if (notificationType === "change") {
handleTypeChange();
} else if (notificationType === "unlock") {
handleTypeUnlock();
}
closeButton?.addEventListener("click", handleCloseNotification);
globalThis.addEventListener("resize", adjustHeight);
adjustHeight();
}
function handleEditOrUpdateAction(e: Event) { function handleEditOrUpdateAction(e: Event) {
const notificationType = initData?.type; const notificationType = initData?.type;
e.preventDefault(); e.preventDefault();
notificationType === "add" ? sendSaveCipherMessage(true) : sendSaveCipherMessage(false); notificationType === "add" ? sendSaveCipherMessage(true) : sendSaveCipherMessage(false);
} }
} }
function handleCloseNotification(e: Event) { function handleCloseNotification(e: Event) {
e.preventDefault(); e.preventDefault();
sendPlatformMessage({ sendPlatformMessage({
command: "bgCloseNotificationBar", command: "bgCloseNotificationBar",
fadeOutNotification: true,
}); });
} }
@@ -439,57 +311,6 @@ function handleSaveAction(e: Event) {
} }
} }
function handleTypeAdd() {
setContent(document.getElementById("template-add") as HTMLTemplateElement);
const addButton = document.getElementById("add-save");
addButton?.addEventListener("click", (e) => {
e.preventDefault();
// If Remove Individual Vault policy applies, "Add" opens the edit tab
sendSaveCipherMessage(removeIndividualVault(), getSelectedFolder());
});
if (removeIndividualVault()) {
// Everything past this point is only required if user has an individual vault
return;
}
const editButton = document.getElementById("add-edit");
editButton?.addEventListener("click", (e) => {
e.preventDefault();
sendSaveCipherMessage(true, getSelectedFolder());
});
const neverButton = document.getElementById("never-save");
neverButton?.addEventListener("click", (e) => {
e.preventDefault();
sendPlatformMessage({
command: "bgNeverSave",
});
});
loadFolderSelector();
}
function handleTypeChange() {
setContent(document.getElementById("template-change") as HTMLTemplateElement);
const changeButton = document.getElementById("change-save");
changeButton?.addEventListener("click", (e) => {
e.preventDefault();
sendSaveCipherMessage(false);
});
const editButton = document.getElementById("change-edit");
editButton?.addEventListener("click", (e) => {
e.preventDefault();
sendSaveCipherMessage(true);
});
}
function sendSaveCipherMessage(edit: boolean, folder?: string) { function sendSaveCipherMessage(edit: boolean, folder?: string) {
sendPlatformMessage({ sendPlatformMessage({
command: "bgSaveCipher", command: "bgSaveCipher",
@@ -498,36 +319,6 @@ function sendSaveCipherMessage(edit: boolean, folder?: string) {
}); });
} }
function handleSaveCipherAttemptCompletedMessage(message: NotificationBarWindowMessage) {
const addSaveButtonContainers = document.querySelectorAll(".add-change-cipher-buttons");
const notificationBarOuterWrapper = document.getElementById("notification-bar-outer-wrapper");
if (message?.error) {
addSaveButtonContainers.forEach((element) => {
element.textContent = chrome.i18n.getMessage("saveCipherAttemptFailed");
element.classList.add("error-message");
notificationBarOuterWrapper?.classList.add("error-event");
});
adjustHeight();
logService.error(`Error encountered when saving credentials: ${message.error}`);
return;
}
const messageName =
notificationBarIframeInitData.type === "add" ? "passwordSaved" : "passwordUpdated";
addSaveButtonContainers.forEach((element) => {
element.textContent = chrome.i18n.getMessage(messageName);
element.prepend(buildSvgDomElement(circleCheckIcon));
element.classList.add("success-message");
notificationBarOuterWrapper?.classList.add("success-event");
});
adjustHeight();
globalThis.setTimeout(
() => sendPlatformMessage({ command: "bgCloseNotificationBar", fadeOutNotification: true }),
3000,
);
}
function openAddEditVaultItemPopout( function openAddEditVaultItemPopout(
e: Event, e: Event,
options: { options: {
@@ -583,27 +374,6 @@ function handleSaveCipherConfirmation(message: NotificationBarWindowMessage) {
); );
} }
function handleTypeUnlock() {
setContent(document.getElementById("template-unlock") as HTMLTemplateElement);
const unlockButton = document.getElementById("unlock-vault");
unlockButton?.addEventListener("click", (e) => {
sendPlatformMessage({
command: "bgReopenUnlockPopout",
});
});
}
function setContent(template: HTMLTemplateElement) {
const content = document.getElementById("content");
while (content?.firstChild) {
content?.removeChild(content.firstChild);
}
const newElement = template.content.cloneNode(true) as HTMLElement;
content?.appendChild(newElement);
}
function sendPlatformMessage( function sendPlatformMessage(
msg: Record<string, unknown>, msg: Record<string, unknown>,
responseCallback?: (response: any) => void, responseCallback?: (response: any) => void,
@@ -615,51 +385,10 @@ function sendPlatformMessage(
}); });
} }
function loadFolderSelector() {
const populateFolderData = (folderData: FolderView[]) => {
const select = document.getElementById("select-folder");
if (!select) {
return;
}
if (!folderData?.length) {
select.appendChild(new Option(chrome.i18n.getMessage("noFoldersFound"), undefined, true));
select.setAttribute("disabled", "true");
return;
}
select.appendChild(new Option(chrome.i18n.getMessage("selectFolder"), undefined, true));
folderData.forEach((folder: FolderView) => {
// Select "No Folder" (id=null) folder by default
select.appendChild(new Option(folder.name, folder.id || "", false));
});
};
sendPlatformMessage({ command: "bgGetFolderData" }, populateFolderData);
}
function getSelectedFolder(): string {
return (document.getElementById("select-folder") as HTMLSelectElement).value;
}
function removeIndividualVault(): boolean { function removeIndividualVault(): boolean {
return Boolean(notificationBarIframeInitData?.removeIndividualVault); return Boolean(notificationBarIframeInitData?.removeIndividualVault);
} }
function adjustHeight() {
const body = document.querySelector("body");
if (!body) {
return;
}
const data: AdjustNotificationBarMessageData = {
height: body.scrollHeight,
};
sendPlatformMessage({
command: "bgAdjustNotificationBar",
data,
});
}
function setupWindowMessageListener() { function setupWindowMessageListener() {
globalThis.addEventListener("message", handleWindowMessage); globalThis.addEventListener("message", handleWindowMessage);
} }
@@ -682,18 +411,6 @@ function handleWindowMessage(event: MessageEvent) {
handler({ message }); handler({ message });
} }
function setupLogoLink(linkText: string) {
const logoLink = document.getElementById("logo-link") as HTMLAnchorElement;
logoLink.title = linkText;
const setWebVaultUrlLink = (webVaultURL: string) => {
const newVaultURL = webVaultURL && decodeURIComponent(webVaultURL);
if (newVaultURL && newVaultURL !== logoLink.href) {
logoLink.href = newVaultURL;
}
};
sendPlatformMessage({ command: "getWebVaultUrlForNotification" }, setWebVaultUrlLink);
}
function getTheme(globalThis: any, theme: NotificationBarIframeInitData["theme"]) { function getTheme(globalThis: any, theme: NotificationBarIframeInitData["theme"]) {
if (theme === ThemeTypes.System) { if (theme === ThemeTypes.System) {
return globalThis.matchMedia("(prefers-color-scheme: dark)").matches return globalThis.matchMedia("(prefers-color-scheme: dark)").matches
@@ -712,12 +429,6 @@ function getResolvedTheme(theme: Theme) {
return resolvedTheme; return resolvedTheme;
} }
function setNotificationBarTheme() {
const theme = getTheme(globalThis, notificationBarIframeInitData.theme);
document.documentElement.classList.add(`theme_${theme}`);
}
function postMessageToParent(message: NotificationBarWindowMessage) { function postMessageToParent(message: NotificationBarWindowMessage) {
globalThis.parent.postMessage(message, windowMessageOrigin || "*"); globalThis.parent.postMessage(message, windowMessageOrigin || "*");
} }

View File

@@ -3,7 +3,7 @@
exports[`OverlayNotificationsContentService opening the notification bar creates the notification bar elements and appends them to the body 1`] = ` exports[`OverlayNotificationsContentService opening the notification bar creates the notification bar elements and appends them to the body 1`] = `
<div <div
id="bit-notification-bar" id="bit-notification-bar"
style="height: 82px !important; width: 430px !important; max-width: calc(100% - 20px) !important; min-height: initial !important; top: 10px !important; right: 10px !important; padding: 0px !important; position: fixed !important; z-index: 2147483647 !important; visibility: visible !important; border-radius: 4px !important; background-color: transparent !important; overflow: hidden !important; transition: box-shadow 0.15s ease !important; transition-delay: 0.15s;" style="height: 400px !important; width: 430px !important; max-width: calc(100% - 20px) !important; min-height: initial !important; top: 10px !important; right: 0px !important; padding: 0px !important; position: fixed !important; z-index: 2147483647 !important; visibility: visible !important; border-radius: 4px !important; background-color: transparent !important; overflow: hidden !important; transition: box-shadow 0.15s ease !important; transition-delay: 0.15s;"
> >
<iframe <iframe
id="bit-notification-bar-iframe" id="bit-notification-bar-iframe"

View File

@@ -1,11 +1,11 @@
import { mock, MockProxy } from "jest-mock-extended"; import { mock, MockProxy } from "jest-mock-extended";
import AutofillInit from "../../../content/autofill-init"; import AutofillInit from "../../../content/autofill-init";
import { NotificationType } from "../../../enums/notification-type.enum";
import { DomQueryService } from "../../../services/abstractions/dom-query.service"; import { DomQueryService } from "../../../services/abstractions/dom-query.service";
import DomElementVisibilityService from "../../../services/dom-element-visibility.service"; import DomElementVisibilityService from "../../../services/dom-element-visibility.service";
import { flushPromises, sendMockExtensionMessage } from "../../../spec/testing-utils"; import { flushPromises, sendMockExtensionMessage } from "../../../spec/testing-utils";
import * as utils from "../../../utils"; import * as utils from "../../../utils";
import { sendExtensionMessage } from "../../../utils";
import { NotificationTypeData } from "../abstractions/overlay-notifications-content.service"; import { NotificationTypeData } from "../abstractions/overlay-notifications-content.service";
import { OverlayNotificationsContentService } from "./overlay-notifications-content.service"; import { OverlayNotificationsContentService } from "./overlay-notifications-content.service";
@@ -19,11 +19,7 @@ describe("OverlayNotificationsContentService", () => {
beforeEach(() => { beforeEach(() => {
jest.useFakeTimers(); jest.useFakeTimers();
jest jest.spyOn(utils, "sendExtensionMessage").mockImplementation(jest.fn());
.spyOn(utils, "sendExtensionMessage")
.mockImplementation((command: string) =>
Promise.resolve(command === "notificationRefreshFlagValue" ? false : true),
);
domQueryService = mock<DomQueryService>(); domQueryService = mock<DomQueryService>();
domElementVisibilityService = new DomElementVisibilityService(); domElementVisibilityService = new DomElementVisibilityService();
overlayNotificationsContentService = new OverlayNotificationsContentService(); overlayNotificationsContentService = new OverlayNotificationsContentService();
@@ -51,37 +47,6 @@ describe("OverlayNotificationsContentService", () => {
expect(bodyAppendChildSpy).not.toHaveBeenCalled(); expect(bodyAppendChildSpy).not.toHaveBeenCalled();
}); });
it("applies correct styles when notificationRefreshFlag is true", async () => {
(sendExtensionMessage as jest.Mock).mockResolvedValue(true);
sendMockExtensionMessage({
command: "openNotificationBar",
data: {
type: "change",
typeData: mock<NotificationTypeData>(),
},
});
await flushPromises();
const barElement = overlayNotificationsContentService["notificationBarElement"]!;
expect(barElement.style.height).toBe("400px");
expect(barElement.style.right).toBe("0px");
});
it("applies correct styles when notificationRefreshFlag is false", async () => {
sendMockExtensionMessage({
command: "openNotificationBar",
data: {
type: "change",
typeData: mock<NotificationTypeData>(),
},
});
await flushPromises();
const barElement = overlayNotificationsContentService["notificationBarElement"]!;
expect(barElement.style.height).toBe("82px");
expect(barElement.style.right).toBe("10px");
});
it("closes the notification bar if the notification bar type has changed", async () => { it("closes the notification bar if the notification bar type has changed", async () => {
overlayNotificationsContentService["currentNotificationBarType"] = "add"; overlayNotificationsContentService["currentNotificationBarType"] = "add";
const closeNotificationBarSpy = jest.spyOn( const closeNotificationBarSpy = jest.spyOn(
@@ -92,7 +57,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -105,7 +70,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -118,7 +83,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>({ typeData: mock<NotificationTypeData>({
launchTimestamp: Date.now(), launchTimestamp: Date.now(),
}), }),
@@ -135,7 +100,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -154,7 +119,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -211,8 +176,21 @@ describe("OverlayNotificationsContentService", () => {
).toBe("0"); ).toBe("0");
jest.advanceTimersByTime(150); jest.advanceTimersByTime(150);
});
expect(sendExtensionMessage).toHaveBeenCalledWith("bgRemoveTabFromNotificationQueue"); it("triggers a fadeout of the notification bar and removes from the notification queue", () => {
sendMockExtensionMessage({
command: "closeNotificationBar",
data: { fadeOutNotification: true, type: NotificationType.ChangePassword },
});
expect(
overlayNotificationsContentService["notificationBarIframeElement"]?.style.opacity,
).toBe("0");
jest.advanceTimersByTime(150);
expect(utils.sendExtensionMessage).toHaveBeenCalledWith("bgRemoveTabFromNotificationQueue");
}); });
it("closes the notification bar without a fadeout", () => { it("closes the notification bar without a fadeout", () => {
@@ -232,7 +210,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -256,7 +234,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });
@@ -286,7 +264,7 @@ describe("OverlayNotificationsContentService", () => {
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "openNotificationBar", command: "openNotificationBar",
data: { data: {
type: "change", type: NotificationType.ChangePassword,
typeData: mock<NotificationTypeData>(), typeData: mock<NotificationTypeData>(),
}, },
}); });

View File

@@ -20,33 +20,25 @@ export class OverlayNotificationsContentService
private notificationBarElement: HTMLElement | null = null; private notificationBarElement: HTMLElement | null = null;
private notificationBarIframeElement: HTMLIFrameElement | null = null; private notificationBarIframeElement: HTMLIFrameElement | null = null;
private currentNotificationBarType: NotificationType | null = null; private currentNotificationBarType: NotificationType | null = null;
private notificationRefreshFlag: boolean = false; private notificationBarContainerStyles: Partial<CSSStyleDeclaration> = {
private getNotificationBarStyles(): Partial<CSSStyleDeclaration> { height: "400px",
const styles: Partial<CSSStyleDeclaration> = { width: "430px",
height: "400px", maxWidth: "calc(100% - 20px)",
width: "430px", minHeight: "initial",
maxWidth: "calc(100% - 20px)", top: "10px",
minHeight: "initial", right: "0px",
top: "10px", padding: "0",
right: "0px", position: "fixed",
padding: "0", zIndex: "2147483647",
position: "fixed", visibility: "visible",
zIndex: "2147483647", borderRadius: "4px",
visibility: "visible", border: "none",
borderRadius: "4px", backgroundColor: "transparent",
border: "none", overflow: "hidden",
backgroundColor: "transparent", transition: "box-shadow 0.15s ease",
overflow: "hidden", transitionDelay: "0.15s",
transition: "box-shadow 0.15s ease", };
transitionDelay: "0.15s",
};
if (!this.notificationRefreshFlag) {
styles.height = "82px";
styles.right = "10px";
}
return styles;
}
private notificationBarIframeElementStyles: Partial<CSSStyleDeclaration> = { private notificationBarIframeElementStyles: Partial<CSSStyleDeclaration> = {
width: "100%", width: "100%",
height: "100%", height: "100%",
@@ -57,6 +49,7 @@ export class OverlayNotificationsContentService
borderRadius: "4px", borderRadius: "4px",
colorScheme: "auto", colorScheme: "auto",
}; };
private readonly extensionMessageHandlers: OverlayNotificationsExtensionMessageHandlers = { private readonly extensionMessageHandlers: OverlayNotificationsExtensionMessageHandlers = {
openNotificationBar: ({ message }) => this.handleOpenNotificationBarMessage(message), openNotificationBar: ({ message }) => this.handleOpenNotificationBarMessage(message),
closeNotificationBar: ({ message }) => this.handleCloseNotificationBarMessage(message), closeNotificationBar: ({ message }) => this.handleCloseNotificationBarMessage(message),
@@ -91,6 +84,7 @@ export class OverlayNotificationsContentService
if (this.currentNotificationBarType && type !== this.currentNotificationBarType) { if (this.currentNotificationBarType && type !== this.currentNotificationBarType) {
this.closeNotificationBar(); this.closeNotificationBar();
} }
const initData = { const initData = {
type: type as NotificationType, type: type as NotificationType,
isVaultLocked: typeData.isVaultLocked, isVaultLocked: typeData.isVaultLocked,
@@ -101,10 +95,6 @@ export class OverlayNotificationsContentService
params, params,
}; };
await sendExtensionMessage("notificationRefreshFlagValue").then((notificationRefreshFlag) => {
this.notificationRefreshFlag = !!notificationRefreshFlag;
});
if (globalThis.document.readyState === "loading") { if (globalThis.document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => this.openNotificationBar(initData)); document.addEventListener("DOMContentLoaded", () => this.openNotificationBar(initData));
return; return;
@@ -215,14 +205,8 @@ export class OverlayNotificationsContentService
{ transform: "translateX(0)", opacity: "1" }, { transform: "translateX(0)", opacity: "1" },
true, true,
); );
if (!this.notificationRefreshFlag) {
setElementStyles( this.notificationBarIframeElement?.removeEventListener(
this.notificationBarElement,
{ boxShadow: "2px 4px 6px 0px #0000001A" },
true,
);
}
this.notificationBarIframeElement.removeEventListener(
EVENTS.LOAD, EVENTS.LOAD,
this.handleNotificationBarIframeOnLoad, this.handleNotificationBarIframeOnLoad,
); );
@@ -236,7 +220,7 @@ export class OverlayNotificationsContentService
this.notificationBarElement = globalThis.document.createElement("div"); this.notificationBarElement = globalThis.document.createElement("div");
this.notificationBarElement.id = "bit-notification-bar"; this.notificationBarElement.id = "bit-notification-bar";
setElementStyles(this.notificationBarElement, this.getNotificationBarStyles(), true); setElementStyles(this.notificationBarElement, this.notificationBarContainerStyles, true);
this.notificationBarElement.appendChild(this.notificationBarIframeElement); this.notificationBarElement.appendChild(this.notificationBarIframeElement);
} }

View File

@@ -83,8 +83,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
unsetMostRecentlyFocusedField: () => this.unsetMostRecentlyFocusedField(), unsetMostRecentlyFocusedField: () => this.unsetMostRecentlyFocusedField(),
checkIsMostRecentlyFocusedFieldWithinViewport: () => checkIsMostRecentlyFocusedFieldWithinViewport: () =>
this.checkIsMostRecentlyFocusedFieldWithinViewport(), this.checkIsMostRecentlyFocusedFieldWithinViewport(),
bgUnlockPopoutOpened: () => this.blurMostRecentlyFocusedField(true),
bgVaultItemRepromptPopoutOpened: () => this.blurMostRecentlyFocusedField(true), bgVaultItemRepromptPopoutOpened: () => this.blurMostRecentlyFocusedField(true),
bgUnlockPopoutOpened: () => this.blurMostRecentlyFocusedField(true),
redirectAutofillInlineMenuFocusOut: ({ message }) => redirectAutofillInlineMenuFocusOut: ({ message }) =>
this.redirectInlineMenuFocusOut(message?.data?.direction), this.redirectInlineMenuFocusOut(message?.data?.direction),
getSubFrameOffsets: ({ message }) => this.getSubFrameOffsets(message), getSubFrameOffsets: ({ message }) => this.getSubFrameOffsets(message),

View File

@@ -18,7 +18,6 @@ export enum FeatureFlag {
PM14938_BrowserExtensionLoginApproval = "pm-14938-browser-extension-login-approvals", PM14938_BrowserExtensionLoginApproval = "pm-14938-browser-extension-login-approvals",
/* Autofill */ /* Autofill */
NotificationRefresh = "notification-refresh",
MacOsNativeCredentialSync = "macos-native-credential-sync", MacOsNativeCredentialSync = "macos-native-credential-sync",
WindowsDesktopAutotype = "windows-desktop-autotype", WindowsDesktopAutotype = "windows-desktop-autotype",
@@ -75,7 +74,6 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.CollectionVaultRefactor]: FALSE, [FeatureFlag.CollectionVaultRefactor]: FALSE,
/* Autofill */ /* Autofill */
[FeatureFlag.NotificationRefresh]: FALSE,
[FeatureFlag.MacOsNativeCredentialSync]: FALSE, [FeatureFlag.MacOsNativeCredentialSync]: FALSE,
[FeatureFlag.WindowsDesktopAutotype]: FALSE, [FeatureFlag.WindowsDesktopAutotype]: FALSE,