From de5f2167f0319bc59999cb3f2fd184f95d2bdcd1 Mon Sep 17 00:00:00 2001 From: Miles Blackwood Date: Fri, 23 Jan 2026 16:47:28 -0500 Subject: [PATCH] Expand generic pattern for notification queue messages. --- .../abstractions/notification.background.ts | 73 +++++++++---------- .../notification.background.spec.ts | 31 +++++--- .../background/notification.background.ts | 37 ++++++---- 3 files changed, 78 insertions(+), 63 deletions(-) diff --git a/apps/browser/src/autofill/background/abstractions/notification.background.ts b/apps/browser/src/autofill/background/abstractions/notification.background.ts index e50a317e8a7..e4558f17803 100644 --- a/apps/browser/src/autofill/background/abstractions/notification.background.ts +++ b/apps/browser/src/autofill/background/abstractions/notification.background.ts @@ -4,62 +4,62 @@ 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 { NotificationType, NotificationTypes } from "../../enums/notification-type.enum"; +import { NotificationType } from "../../enums/notification-type.enum"; import AutofillPageDetails from "../../models/autofill-page-details"; /** - * @todo Remove Standard_ label when implemented as standard NotificationQueueMessage. + * Generic notification queue message structure. + * All notification types use this structure with type-specific data. */ -export interface Standard_NotificationQueueMessage { - // universal notification properties +export interface NotificationQueueMessage { domain: string; tab: chrome.tabs.Tab; launchTimestamp: number; expires: Date; wasVaultLocked: boolean; - - type: T; // NotificationType - data: D; // notification-specific data + type: T; + data: D; } -/** - * @todo Deprecate in favor of Standard_NotificationQueueMessage. - */ -interface NotificationQueueMessage { - type: NotificationTypes; - domain: string; - tab: chrome.tabs.Tab; - launchTimestamp: number; - expires: Date; - wasVaultLocked: boolean; -} +// Notification data type definitions +export type AddLoginNotificationData = { + username: string; + password: string; + uri: string; +}; -type ChangePasswordNotificationData = { +export type ChangePasswordNotificationData = { cipherIds: CipherView["id"][]; newPassword: string; }; -type AddChangePasswordNotificationQueueMessage = Standard_NotificationQueueMessage< +export type UnlockVaultNotificationData = never; + +export type AtRiskPasswordNotificationData = { + organizationName: string; + passwordChangeUri?: string; +}; + +// Notification queue message types using generic pattern +export type AddLoginQueueMessage = NotificationQueueMessage< + typeof NotificationType.AddLogin, + AddLoginNotificationData +>; + +export type AddChangePasswordNotificationQueueMessage = NotificationQueueMessage< typeof NotificationType.ChangePassword, ChangePasswordNotificationData >; -interface AddLoginQueueMessage extends NotificationQueueMessage { - type: "add"; - username: string; - password: string; - uri: string; -} +export type AddUnlockVaultQueueMessage = NotificationQueueMessage< + typeof NotificationType.UnlockVault, + UnlockVaultNotificationData +>; -interface AddUnlockVaultQueueMessage extends NotificationQueueMessage { - type: "unlock"; -} - -interface AtRiskPasswordQueueMessage extends NotificationQueueMessage { - type: "at-risk-password"; - organizationName: string; - passwordChangeUri?: string; -} +export type AtRiskPasswordQueueMessage = NotificationQueueMessage< + typeof NotificationType.AtRiskPassword, + AtRiskPasswordNotificationData +>; type NotificationQueueMessageItem = | AddLoginQueueMessage @@ -152,9 +152,6 @@ type NotificationBackgroundExtensionMessageHandlers = { }; export { - AddChangePasswordNotificationQueueMessage, - AddLoginQueueMessage, - AddUnlockVaultQueueMessage, NotificationQueueMessageItem, LockedVaultPendingNotificationsData, AdjustNotificationBarMessageData, diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index ab16788ea6f..b5ed91e704a 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -122,9 +122,11 @@ describe("NotificationBackground", () => { it("returns a cipher view when passed an `AddLoginQueueMessage`", () => { const message: AddLoginQueueMessage = { type: "add", - username: "test", - password: "password", - uri: "https://example.com", + data: { + username: "test", + password: "password", + uri: "https://example.com", + }, domain: "", tab: createChromeTabMock(), expires: new Date(), @@ -136,13 +138,13 @@ describe("NotificationBackground", () => { expect(cipherView.name).toEqual("example.com"); expect(cipherView.login).toEqual({ fido2Credentials: [], - password: message.password, + password: message.data.password, uris: [ { - _uri: message.uri, + _uri: message.data.uri, }, ], - username: message.username, + username: message.data.username, }); }); @@ -150,9 +152,11 @@ describe("NotificationBackground", () => { const folderId = "folder-id"; const message: AddLoginQueueMessage = { type: "add", - username: "test", - password: "password", - uri: "https://example.com", + data: { + username: "test", + password: "password", + uri: "https://example.com", + }, domain: "example.com", tab: createChromeTabMock(), expires: new Date(), @@ -1051,8 +1055,11 @@ describe("NotificationBackground", () => { type: NotificationType.AddLogin, tab, domain: "example.com", - username: "test", - password: "updated-password", + data: { + username: "test", + password: "updated-password", + uri: "https://example.com", + }, wasVaultLocked: true, }); notificationBackground["notificationQueue"] = [queueMessage]; @@ -1066,7 +1073,7 @@ describe("NotificationBackground", () => { expect(updatePasswordSpy).toHaveBeenCalledWith( cipherView, - queueMessage.password, + queueMessage.data.password, message.edit, sender.tab, "testId", diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 1cbf915b06a..c71a231b4da 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -499,12 +499,14 @@ export default class NotificationBackground { this.removeTabFromNotificationQueue(tab); const launchTimestamp = new Date().getTime(); - const queueMessage: NotificationQueueMessageItem = { + const queueMessage: AtRiskPasswordQueueMessage = { domain, wasVaultLocked, type: NotificationType.AtRiskPassword, - passwordChangeUri, - organizationName: organization.name, + data: { + passwordChangeUri, + organizationName: organization.name, + }, tab: tab, launchTimestamp, expires: new Date(launchTimestamp + NOTIFICATION_BAR_LIFESPAN_MS), @@ -583,10 +585,12 @@ export default class NotificationBackground { const launchTimestamp = new Date().getTime(); const message: AddLoginQueueMessage = { type: NotificationType.AddLogin, - username: loginInfo.username, - password: loginInfo.password, + data: { + username: loginInfo.username, + password: loginInfo.password, + uri: loginInfo.url, + }, domain: loginDomain, - uri: loginInfo.url, tab: tab, launchTimestamp, expires: new Date(launchTimestamp + NOTIFICATION_BAR_LIFESPAN_MS), @@ -843,16 +847,23 @@ export default class NotificationBackground { // If the vault was locked, check if a cipher needs updating instead of creating a new one if (queueMessage.wasVaultLocked) { const allCiphers = await this.cipherService.getAllDecryptedForUrl( - queueMessage.uri, + queueMessage.data.uri, activeUserId, ); const existingCipher = allCiphers.find( (c) => - c.login.username != null && c.login.username.toLowerCase() === queueMessage.username, + c.login.username != null && + c.login.username.toLowerCase() === queueMessage.data.username, ); if (existingCipher != null) { - await this.updatePassword(existingCipher, queueMessage.password, edit, tab, activeUserId); + await this.updatePassword( + existingCipher, + queueMessage.data.password, + edit, + tab, + activeUserId, + ); return; } } @@ -1276,15 +1287,15 @@ export default class NotificationBackground { folderId?: string, ): CipherView { const uriView = new LoginUriView(); - uriView.uri = message.uri; + uriView.uri = message.data.uri; const loginView = new LoginView(); loginView.uris = [uriView]; - loginView.username = message.username; - loginView.password = message.password; + loginView.username = message.data.username; + loginView.password = message.data.password; const cipherView = new CipherView(); - cipherView.name = (Utils.getHostname(message.uri) || message.domain).replace(/^www\./, ""); + cipherView.name = (Utils.getHostname(message.data.uri) || message.domain).replace(/^www\./, ""); cipherView.folderId = folderId; cipherView.type = CipherType.Login; cipherView.login = loginView;