diff --git a/apps/browser/src/autofill/background/abstractions/notification.background.ts b/apps/browser/src/autofill/background/abstractions/notification.background.ts index 571d9fbaf5f..cc28ed0057e 100644 --- a/apps/browser/src/autofill/background/abstractions/notification.background.ts +++ b/apps/browser/src/autofill/background/abstractions/notification.background.ts @@ -4,11 +4,29 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { CollectionView } from "../../content/components/common-types"; -import { NotificationQueueMessageTypes } from "../../enums/notification-queue-message-type.enum"; +import { NotificationType, NotificationTypes } from "../../enums/notification-type.enum"; import AutofillPageDetails from "../../models/autofill-page-details"; +/** + * @todo Remove Standard_ label when implemented as standard NotificationQueueMessage. + */ +export interface Standard_NotificationQueueMessage { + // universal notification properties + domain: string; + tab: chrome.tabs.Tab; + launchTimestamp: number; + expires: Date; + wasVaultLocked: boolean; + + type: T; // NotificationType + data: D; // notification-specific data +} + +/** + * @todo Deprecate in favor of Standard_NotificationQueueMessage. + */ interface NotificationQueueMessage { - type: NotificationQueueMessageTypes; + type: NotificationTypes; domain: string; tab: chrome.tabs.Tab; launchTimestamp: number; @@ -16,11 +34,15 @@ interface NotificationQueueMessage { wasVaultLocked: boolean; } -interface AddChangePasswordQueueMessage extends NotificationQueueMessage { - type: "change"; +type ChangePasswordNotificationData = { cipherId: CipherView["id"]; newPassword: string; -} +}; + +type AddChangePasswordNotificationQueueMessage = Standard_NotificationQueueMessage< + typeof NotificationType.ChangePassword, + ChangePasswordNotificationData +>; interface AddLoginQueueMessage extends NotificationQueueMessage { type: "add"; @@ -41,7 +63,7 @@ interface AtRiskPasswordQueueMessage extends NotificationQueueMessage { type NotificationQueueMessageItem = | AddLoginQueueMessage - | AddChangePasswordQueueMessage + | AddChangePasswordNotificationQueueMessage | AddUnlockVaultQueueMessage | AtRiskPasswordQueueMessage; @@ -72,6 +94,11 @@ type UnlockVaultMessageData = { skipNotification?: boolean; }; +/** + * @todo Extend generics to this type, see Standard_NotificationQueueMessage + * - use new `data` types as generic + * - eliminate optional status of properties as needed per Notification Type + */ type NotificationBackgroundExtensionMessage = { [key: string]: any; command: string; @@ -126,7 +153,7 @@ type NotificationBackgroundExtensionMessageHandlers = { }; export { - AddChangePasswordQueueMessage, + AddChangePasswordNotificationQueueMessage, AddLoginQueueMessage, AddUnlockVaultQueueMessage, NotificationQueueMessageItem, diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index 7302ae7d705..1c72b2af1d1 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -26,14 +26,14 @@ import { FolderService } from "@bitwarden/common/vault/services/folder/folder.se import { TaskService, SecurityTask } from "@bitwarden/common/vault/tasks"; import { BrowserApi } from "../../platform/browser/browser-api"; -import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; +import { NotificationType } from "../enums/notification-type.enum"; import { FormData } from "../services/abstractions/autofill.service"; import AutofillService from "../services/autofill.service"; import { createAutofillPageDetailsMock, createChromeTabMock } from "../spec/autofill-mocks"; import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils"; import { - AddChangePasswordQueueMessage, + AddChangePasswordNotificationQueueMessage, AddLoginQueueMessage, AddUnlockVaultQueueMessage, LockedVaultPendingNotificationsData, @@ -761,7 +761,7 @@ describe("NotificationBackground", () => { notificationBackground["notificationQueue"] = [ mock({ tab, - type: NotificationQueueMessageType.UnlockVault, + type: NotificationType.UnlockVault, }), ]; @@ -783,7 +783,7 @@ describe("NotificationBackground", () => { }; notificationBackground["notificationQueue"] = [ mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "another.com", }), @@ -803,11 +803,11 @@ describe("NotificationBackground", () => { edit: false, folder: "folder-id", }; - const queueMessage = mock({ - type: NotificationQueueMessageType.ChangePassword, + const queueMessage = mock({ + type: NotificationType.ChangePassword, tab, domain: "example.com", - newPassword: "newPassword", + data: { newPassword: "newPassword" }, }); notificationBackground["notificationQueue"] = [queueMessage]; const cipherView = mock({ @@ -825,7 +825,7 @@ describe("NotificationBackground", () => { expect(createWithServerSpy).not.toHaveBeenCalled(); expect(updatePasswordSpy).toHaveBeenCalledWith( cipherView, - queueMessage.newPassword, + queueMessage.data.newPassword, message.edit, sender.tab, "testId", @@ -851,11 +851,11 @@ describe("NotificationBackground", () => { edit: false, folder: "folder-id", }; - const queueMessage = mock({ - type: NotificationQueueMessageType.ChangePassword, + const queueMessage = mock({ + type: NotificationType.ChangePassword, tab, domain: "example.com", - newPassword: "newPassword", + data: { newPassword: "newPassword" }, }); notificationBackground["notificationQueue"] = [queueMessage]; const cipherView = mock({ @@ -874,7 +874,7 @@ describe("NotificationBackground", () => { expect(createWithServerSpy).not.toHaveBeenCalled(); expect(updatePasswordSpy).toHaveBeenCalledWith( cipherView, - queueMessage.newPassword, + queueMessage.data.newPassword, message.edit, sender.tab, "testId", @@ -931,11 +931,11 @@ describe("NotificationBackground", () => { edit: false, folder: "folder-id", }; - const queueMessage = mock({ - type: NotificationQueueMessageType.ChangePassword, + const queueMessage = mock({ + type: NotificationType.ChangePassword, tab, domain: "example.com", - newPassword: "newPassword", + data: { newPassword: "newPassword" }, }); notificationBackground["notificationQueue"] = [queueMessage]; const cipherView = mock({ @@ -953,7 +953,7 @@ describe("NotificationBackground", () => { expect(createWithServerSpy).not.toHaveBeenCalled(); expect(updatePasswordSpy).toHaveBeenCalledWith( cipherView, - queueMessage.newPassword, + queueMessage.data.newPassword, message.edit, sender.tab, mockCipherId, @@ -983,7 +983,7 @@ describe("NotificationBackground", () => { folder: "folder-id", }; const queueMessage = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "example.com", username: "test", @@ -1018,11 +1018,11 @@ describe("NotificationBackground", () => { edit: true, folder: "folder-id", }; - const queueMessage = mock({ - type: NotificationQueueMessageType.ChangePassword, + const queueMessage = mock({ + type: NotificationType.ChangePassword, tab, domain: "example.com", - newPassword: "newPassword", + data: { newPassword: "newPassword" }, }); notificationBackground["notificationQueue"] = [queueMessage]; const cipherView = mock(); @@ -1035,7 +1035,7 @@ describe("NotificationBackground", () => { expect(updatePasswordSpy).toHaveBeenCalledWith( cipherView, - queueMessage.newPassword, + queueMessage.data.newPassword, message.edit, sender.tab, "testId", @@ -1070,7 +1070,7 @@ describe("NotificationBackground", () => { folder: "folder-id", }; const queueMessage = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "example.com", username: "test", @@ -1109,7 +1109,7 @@ describe("NotificationBackground", () => { folder: "folder-id", }; const queueMessage = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "example.com", username: "test", @@ -1162,7 +1162,7 @@ describe("NotificationBackground", () => { folder: "folder-id", }; const queueMessage = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "example.com", username: "test", @@ -1213,11 +1213,11 @@ describe("NotificationBackground", () => { edit: false, folder: "folder-id", }; - const queueMessage = mock({ - type: NotificationQueueMessageType.ChangePassword, + const queueMessage = mock({ + type: NotificationType.ChangePassword, tab, domain: "example.com", - newPassword: "newPassword", + data: { newPassword: "newPassword" }, }); notificationBackground["notificationQueue"] = [queueMessage]; const cipherView = mock({ reprompt: CipherRepromptType.None }); @@ -1273,7 +1273,7 @@ describe("NotificationBackground", () => { const sender = mock({ tab }); const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" }; notificationBackground["notificationQueue"] = [ - mock({ type: NotificationQueueMessageType.UnlockVault, tab }), + mock({ type: NotificationType.UnlockVault, tab }), ]; sendMockExtensionMessage(message, sender); @@ -1289,7 +1289,7 @@ describe("NotificationBackground", () => { const sender = mock({ tab: secondaryTab }); notificationBackground["notificationQueue"] = [ mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "another.com", }), @@ -1306,12 +1306,12 @@ describe("NotificationBackground", () => { const sender = mock({ tab }); const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" }; const firstNotification = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab, domain: "example.com", }); const secondNotification = mock({ - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, tab: createChromeTabMock({ id: 3 }), domain: "another.com", }); diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 3f6e93d8454..e9eea552f37 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -60,12 +60,12 @@ import { NotificationCipherData, } from "../content/components/cipher/types"; import { CollectionView } from "../content/components/common-types"; -import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum"; +import { NotificationType } from "../enums/notification-type.enum"; import { AutofillService } from "../services/abstractions/autofill.service"; import { TemporaryNotificationChangeLoginService } from "../services/notification-change-login-password.service"; import { - AddChangePasswordQueueMessage, + AddChangePasswordNotificationQueueMessage, AddLoginQueueMessage, AddUnlockVaultQueueMessage, AddLoginMessageData, @@ -208,16 +208,21 @@ export default class NotificationBackground { organizations.find((org) => org.id === orgId)?.productTierType; const cipherQueueMessage = this.notificationQueue.find( - (message): message is AddChangePasswordQueueMessage | AddLoginQueueMessage => - message.type === NotificationQueueMessageType.ChangePassword || - message.type === NotificationQueueMessageType.AddLogin, + (message): message is AddChangePasswordNotificationQueueMessage | AddLoginQueueMessage => + message.type === NotificationType.ChangePassword || + message.type === NotificationType.AddLogin, ); if (cipherQueueMessage) { - const cipherView = - cipherQueueMessage.type === NotificationQueueMessageType.ChangePassword - ? await this.getDecryptedCipherById(cipherQueueMessage.cipherId, activeUserId) - : this.convertAddLoginQueueMessageToCipherView(cipherQueueMessage); + let cipherView: CipherView; + if (cipherQueueMessage.type === NotificationType.ChangePassword) { + const { + data: { cipherId }, + } = cipherQueueMessage; + cipherView = await this.getDecryptedCipherById(cipherId, activeUserId); + } else { + cipherView = this.convertAddLoginQueueMessageToCipherView(cipherQueueMessage); + } const organizationType = getOrganizationType(cipherView.organizationId); return [ @@ -424,7 +429,7 @@ export default class NotificationBackground { }; switch (notificationType) { - case NotificationQueueMessageType.AddLogin: + case NotificationType.AddLogin: typeData.removeIndividualVault = await this.removeIndividualVault(); break; } @@ -501,7 +506,7 @@ export default class NotificationBackground { const queueMessage: NotificationQueueMessageItem = { domain, wasVaultLocked, - type: NotificationQueueMessageType.AtRiskPassword, + type: NotificationType.AtRiskPassword, passwordChangeUri, organizationName: organization.name, tab: tab, @@ -591,7 +596,7 @@ export default class NotificationBackground { this.removeTabFromNotificationQueue(tab); const launchTimestamp = new Date().getTime(); const message: AddLoginQueueMessage = { - type: NotificationQueueMessageType.AddLogin, + type: NotificationType.AddLogin, username: loginInfo.username, password: loginInfo.password, domain: loginDomain, @@ -716,10 +721,9 @@ export default class NotificationBackground { // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); const launchTimestamp = new Date().getTime(); - const message: AddChangePasswordQueueMessage = { - type: NotificationQueueMessageType.ChangePassword, - cipherId: cipherId, - newPassword: newPassword, + const message: AddChangePasswordNotificationQueueMessage = { + type: NotificationType.ChangePassword, + data: { cipherId: cipherId, newPassword: newPassword }, domain: loginDomain, tab: tab, launchTimestamp, @@ -734,7 +738,7 @@ export default class NotificationBackground { this.removeTabFromNotificationQueue(tab); const launchTimestamp = new Date().getTime(); const message: AddUnlockVaultQueueMessage = { - type: NotificationQueueMessageType.UnlockVault, + type: NotificationType.UnlockVault, domain: loginDomain, tab: tab, launchTimestamp, @@ -804,8 +808,8 @@ export default class NotificationBackground { const queueMessage = this.notificationQueue[i]; if ( queueMessage.tab.id !== tab.id || - (queueMessage.type !== NotificationQueueMessageType.AddLogin && - queueMessage.type !== NotificationQueueMessageType.ChangePassword) + (queueMessage.type !== NotificationType.AddLogin && + queueMessage.type !== NotificationType.ChangePassword) ) { continue; } @@ -818,17 +822,13 @@ export default class NotificationBackground { this.accountService.activeAccount$.pipe(getOptionalUserId), ); - if (queueMessage.type === NotificationQueueMessageType.ChangePassword) { - const cipherView = await this.getDecryptedCipherById(queueMessage.cipherId, activeUserId); + if (queueMessage.type === NotificationType.ChangePassword) { + const { + data: { cipherId, newPassword }, + } = queueMessage; + const cipherView = await this.getDecryptedCipherById(cipherId, activeUserId); - await this.updatePassword( - cipherView, - queueMessage.newPassword, - edit, - tab, - activeUserId, - skipReprompt, - ); + await this.updatePassword(cipherView, newPassword, edit, tab, activeUserId, skipReprompt); return; } @@ -993,7 +993,7 @@ export default class NotificationBackground { const queueItem = this.notificationQueue.find((item) => item.tab.id === senderTab.id); - if (queueItem?.type === NotificationQueueMessageType.AddLogin) { + if (queueItem?.type === NotificationType.AddLogin) { const cipherView = this.convertAddLoginQueueMessageToCipherView(queueItem); cipherView.organizationId = organizationId; cipherView.folderId = folder; @@ -1075,10 +1075,7 @@ export default class NotificationBackground { private async saveNever(tab: chrome.tabs.Tab) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; - if ( - queueMessage.tab.id !== tab.id || - queueMessage.type !== NotificationQueueMessageType.AddLogin - ) { + if (queueMessage.tab.id !== tab.id || queueMessage.type !== NotificationType.AddLogin) { continue; } diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 4027689f014..617275da060 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -1866,7 +1866,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { frameId: this.focusedFieldData.frameId || 0, }, ); - }, 150); + }, 300); } /** diff --git a/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts b/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts deleted file mode 100644 index 1fe6246f8b8..00000000000 --- a/apps/browser/src/autofill/enums/notification-queue-message-type.enum.ts +++ /dev/null @@ -1,11 +0,0 @@ -const NotificationQueueMessageType = { - AddLogin: "add", - ChangePassword: "change", - UnlockVault: "unlock", - AtRiskPassword: "at-risk-password", -} as const; - -type NotificationQueueMessageTypes = - (typeof NotificationQueueMessageType)[keyof typeof NotificationQueueMessageType]; - -export { NotificationQueueMessageType, NotificationQueueMessageTypes }; diff --git a/apps/browser/src/autofill/enums/notification-type.enum.ts b/apps/browser/src/autofill/enums/notification-type.enum.ts new file mode 100644 index 00000000000..a82adcea402 --- /dev/null +++ b/apps/browser/src/autofill/enums/notification-type.enum.ts @@ -0,0 +1,10 @@ +const NotificationType = { + AddLogin: "add", + ChangePassword: "change", + UnlockVault: "unlock", + AtRiskPassword: "at-risk-password", +} as const; + +type NotificationTypes = (typeof NotificationType)[keyof typeof NotificationType]; + +export { NotificationType, NotificationTypes }; diff --git a/apps/browser/src/autofill/notification/abstractions/notification-bar.ts b/apps/browser/src/autofill/notification/abstractions/notification-bar.ts index 934aa4a2571..7881d2f1cac 100644 --- a/apps/browser/src/autofill/notification/abstractions/notification-bar.ts +++ b/apps/browser/src/autofill/notification/abstractions/notification-bar.ts @@ -14,6 +14,10 @@ const NotificationTypes = { AtRiskPassword: "at-risk-password", } as const; +/** + * @todo Deprecate in favor of apps/browser/src/autofill/enums/notification-type.enum.ts + * - Determine fix or workaround for restricted imports of that file. + */ type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes]; type NotificationTaskInfo = { @@ -21,6 +25,9 @@ type NotificationTaskInfo = { remainingTasksCount: number; }; +/** + * @todo Use generics to make this type specific to notification types, see Standard_NotificationQueueMessage. + */ type NotificationBarIframeInitData = { ciphers?: NotificationCipherData[]; folders?: FolderView[];