1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 21:33:27 +00:00

Creates notification queue type standard. (#16009)

This commit is contained in:
Miles Blackwood
2025-08-14 18:43:48 -04:00
committed by GitHub
parent ff4952c113
commit 89f797d45f
7 changed files with 114 additions and 84 deletions

View File

@@ -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<T, D> {
// 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,

View File

@@ -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<AddUnlockVaultQueueMessage>({
tab,
type: NotificationQueueMessageType.UnlockVault,
type: NotificationType.UnlockVault,
}),
];
@@ -783,7 +783,7 @@ describe("NotificationBackground", () => {
};
notificationBackground["notificationQueue"] = [
mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab,
domain: "another.com",
}),
@@ -803,11 +803,11 @@ describe("NotificationBackground", () => {
edit: false,
folder: "folder-id",
};
const queueMessage = mock<AddChangePasswordQueueMessage>({
type: NotificationQueueMessageType.ChangePassword,
const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationType.ChangePassword,
tab,
domain: "example.com",
newPassword: "newPassword",
data: { newPassword: "newPassword" },
});
notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({
@@ -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<AddChangePasswordQueueMessage>({
type: NotificationQueueMessageType.ChangePassword,
const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationType.ChangePassword,
tab,
domain: "example.com",
newPassword: "newPassword",
data: { newPassword: "newPassword" },
});
notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({
@@ -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<AddChangePasswordQueueMessage>({
type: NotificationQueueMessageType.ChangePassword,
const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationType.ChangePassword,
tab,
domain: "example.com",
newPassword: "newPassword",
data: { newPassword: "newPassword" },
});
notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({
@@ -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<AddLoginQueueMessage>({
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<AddChangePasswordQueueMessage>({
type: NotificationQueueMessageType.ChangePassword,
const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationType.ChangePassword,
tab,
domain: "example.com",
newPassword: "newPassword",
data: { newPassword: "newPassword" },
});
notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>();
@@ -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<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab,
domain: "example.com",
username: "test",
@@ -1109,7 +1109,7 @@ describe("NotificationBackground", () => {
folder: "folder-id",
};
const queueMessage = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab,
domain: "example.com",
username: "test",
@@ -1162,7 +1162,7 @@ describe("NotificationBackground", () => {
folder: "folder-id",
};
const queueMessage = mock<AddLoginQueueMessage>({
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<AddChangePasswordQueueMessage>({
type: NotificationQueueMessageType.ChangePassword,
const queueMessage = mock<AddChangePasswordNotificationQueueMessage>({
type: NotificationType.ChangePassword,
tab,
domain: "example.com",
newPassword: "newPassword",
data: { newPassword: "newPassword" },
});
notificationBackground["notificationQueue"] = [queueMessage];
const cipherView = mock<CipherView>({ reprompt: CipherRepromptType.None });
@@ -1273,7 +1273,7 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab });
const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" };
notificationBackground["notificationQueue"] = [
mock<AddUnlockVaultQueueMessage>({ type: NotificationQueueMessageType.UnlockVault, tab }),
mock<AddUnlockVaultQueueMessage>({ type: NotificationType.UnlockVault, tab }),
];
sendMockExtensionMessage(message, sender);
@@ -1289,7 +1289,7 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab: secondaryTab });
notificationBackground["notificationQueue"] = [
mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab,
domain: "another.com",
}),
@@ -1306,12 +1306,12 @@ describe("NotificationBackground", () => {
const sender = mock<chrome.runtime.MessageSender>({ tab });
const message: NotificationBackgroundExtensionMessage = { command: "bgNeverSave" };
const firstNotification = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab,
domain: "example.com",
});
const secondNotification = mock<AddLoginQueueMessage>({
type: NotificationQueueMessageType.AddLogin,
type: NotificationType.AddLogin,
tab: createChromeTabMock({ id: 3 }),
domain: "another.com",
});

View File

@@ -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;
}

View File

@@ -1866,7 +1866,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
frameId: this.focusedFieldData.frameId || 0,
},
);
}, 150);
}, 300);
}
/**

View File

@@ -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 };

View File

@@ -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 };

View File

@@ -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[];