mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 14:53:33 +00:00
[PM-5949] Refactor Typing Information for Notification Bar (#7722)
* [PM-5949] Refactor typing information for notification bar * [PM-5949] Fix jest tests for overlay background * [PM-5949] Removing unnused typing data * [PM-5949] Fixing lint error * [PM-5949] Adding jest tests for convertAddLoginQueueMessageToCipherView method * [PM-5949] Fixing jest test for overlay
This commit is contained in:
@@ -1,7 +1,34 @@
|
|||||||
import AddChangePasswordQueueMessage from "../../notification/models/add-change-password-queue-message";
|
import { NotificationQueueMessageTypes } from "../../enums/notification-queue-message-type.enum";
|
||||||
import AddLoginQueueMessage from "../../notification/models/add-login-queue-message";
|
|
||||||
import AddRequestFilelessImportQueueMessage from "../../notification/models/add-request-fileless-import-queue-message";
|
interface NotificationQueueMessage {
|
||||||
import AddUnlockVaultQueueMessage from "../../notification/models/add-unlock-vault-queue-message";
|
type: NotificationQueueMessageTypes;
|
||||||
|
domain: string;
|
||||||
|
tab: chrome.tabs.Tab;
|
||||||
|
expires: Date;
|
||||||
|
wasVaultLocked: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddChangePasswordQueueMessage extends NotificationQueueMessage {
|
||||||
|
type: "change";
|
||||||
|
cipherId: string;
|
||||||
|
newPassword: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddLoginQueueMessage extends NotificationQueueMessage {
|
||||||
|
type: "add";
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
uri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddUnlockVaultQueueMessage extends NotificationQueueMessage {
|
||||||
|
type: "unlock";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddRequestFilelessImportQueueMessage extends NotificationQueueMessage {
|
||||||
|
type: "fileless-import";
|
||||||
|
importType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
type NotificationQueueMessageItem =
|
type NotificationQueueMessageItem =
|
||||||
| AddLoginQueueMessage
|
| AddLoginQueueMessage
|
||||||
@@ -9,4 +36,38 @@ type NotificationQueueMessageItem =
|
|||||||
| AddUnlockVaultQueueMessage
|
| AddUnlockVaultQueueMessage
|
||||||
| AddRequestFilelessImportQueueMessage;
|
| AddRequestFilelessImportQueueMessage;
|
||||||
|
|
||||||
export { NotificationQueueMessageItem };
|
type LockedVaultPendingNotificationsData = {
|
||||||
|
commandToRetry: {
|
||||||
|
message: {
|
||||||
|
command: string;
|
||||||
|
contextMenuOnClickData?: chrome.contextMenus.OnClickData;
|
||||||
|
folder?: string;
|
||||||
|
edit?: boolean;
|
||||||
|
};
|
||||||
|
sender: chrome.runtime.MessageSender;
|
||||||
|
};
|
||||||
|
target: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChangePasswordMessageData = {
|
||||||
|
currentPassword: string;
|
||||||
|
newPassword: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AddLoginMessageData = {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
AddChangePasswordQueueMessage,
|
||||||
|
AddLoginQueueMessage,
|
||||||
|
AddUnlockVaultQueueMessage,
|
||||||
|
AddRequestFilelessImportQueueMessage,
|
||||||
|
NotificationQueueMessageItem,
|
||||||
|
LockedVaultPendingNotificationsData,
|
||||||
|
ChangePasswordMessageData,
|
||||||
|
AddLoginMessageData,
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-repromp
|
|||||||
|
|
||||||
import AutofillPageDetails from "../../models/autofill-page-details";
|
import AutofillPageDetails from "../../models/autofill-page-details";
|
||||||
|
|
||||||
|
import { LockedVaultPendingNotificationsData } from "./notification.background";
|
||||||
|
|
||||||
type WebsiteIconData = {
|
type WebsiteIconData = {
|
||||||
imageEnabled: boolean;
|
imageEnabled: boolean;
|
||||||
image: string;
|
image: string;
|
||||||
@@ -27,13 +29,7 @@ type OverlayBackgroundExtensionMessage = {
|
|||||||
details?: AutofillPageDetails;
|
details?: AutofillPageDetails;
|
||||||
overlayElement?: string;
|
overlayElement?: string;
|
||||||
display?: string;
|
display?: string;
|
||||||
data?: {
|
data?: LockedVaultPendingNotificationsData;
|
||||||
commandToRetry?: {
|
|
||||||
msg?: {
|
|
||||||
command?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} & OverlayAddNewItemMessage;
|
} & OverlayAddNewItemMessage;
|
||||||
|
|
||||||
type OverlayPortMessage = {
|
type OverlayPortMessage = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import { ContextMenuClickedHandler } from "../browser/context-menu-clicked-handler";
|
import { ContextMenuClickedHandler } from "../browser/context-menu-clicked-handler";
|
||||||
import LockedVaultPendingNotificationsItem from "../notification/models/locked-vault-pending-notifications-item";
|
|
||||||
|
import { LockedVaultPendingNotificationsData } from "./abstractions/notification.background";
|
||||||
|
|
||||||
export default class ContextMenusBackground {
|
export default class ContextMenusBackground {
|
||||||
private contextMenus: typeof chrome.contextMenus;
|
private contextMenus: typeof chrome.contextMenus;
|
||||||
@@ -21,14 +22,17 @@ export default class ContextMenusBackground {
|
|||||||
BrowserApi.messageListener(
|
BrowserApi.messageListener(
|
||||||
"contextmenus.background",
|
"contextmenus.background",
|
||||||
(
|
(
|
||||||
msg: { command: string; data: LockedVaultPendingNotificationsItem },
|
msg: { command: string; data: LockedVaultPendingNotificationsData },
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
) => {
|
) => {
|
||||||
if (msg.command === "unlockCompleted" && msg.data.target === "contextmenus.background") {
|
if (msg.command === "unlockCompleted" && msg.data.target === "contextmenus.background") {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.contextMenuClickedHandler
|
this.contextMenuClickedHandler
|
||||||
.cipherAction(msg.data.commandToRetry.msg.data, msg.data.commandToRetry.sender.tab)
|
.cipherAction(
|
||||||
|
msg.data.commandToRetry.message.contextMenuOnClickData,
|
||||||
|
msg.data.commandToRetry.sender.tab,
|
||||||
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { BrowserStateService } from "../../platform/services/browser-state.servi
|
|||||||
import { createChromeTabMock } from "../jest/autofill-mocks";
|
import { createChromeTabMock } from "../jest/autofill-mocks";
|
||||||
import AutofillService from "../services/autofill.service";
|
import AutofillService from "../services/autofill.service";
|
||||||
|
|
||||||
|
import { AddLoginQueueMessage } from "./abstractions/notification.background";
|
||||||
import NotificationBackground from "./notification.background";
|
import NotificationBackground from "./notification.background";
|
||||||
|
|
||||||
describe("NotificationBackground", () => {
|
describe("NotificationBackground", () => {
|
||||||
@@ -51,4 +52,60 @@ describe("NotificationBackground", () => {
|
|||||||
expect(notificationBackground["pushUnlockVaultToQueue"]).not.toHaveBeenCalled();
|
expect(notificationBackground["pushUnlockVaultToQueue"]).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("convertAddLoginQueueMessageToCipherView", () => {
|
||||||
|
it("returns a cipher view when passed an `AddLoginQueueMessage`", () => {
|
||||||
|
const message: AddLoginQueueMessage = {
|
||||||
|
type: "add",
|
||||||
|
username: "test",
|
||||||
|
password: "password",
|
||||||
|
uri: "https://example.com",
|
||||||
|
domain: "",
|
||||||
|
tab: createChromeTabMock(),
|
||||||
|
expires: new Date(),
|
||||||
|
wasVaultLocked: false,
|
||||||
|
};
|
||||||
|
const cipherView = notificationBackground["convertAddLoginQueueMessageToCipherView"](message);
|
||||||
|
|
||||||
|
expect(cipherView.name).toEqual("example.com");
|
||||||
|
expect(cipherView.login).toEqual({
|
||||||
|
autofillOnPageLoad: null,
|
||||||
|
fido2Credentials: null,
|
||||||
|
password: message.password,
|
||||||
|
passwordRevisionDate: null,
|
||||||
|
totp: null,
|
||||||
|
uris: [
|
||||||
|
{
|
||||||
|
_canLaunch: null,
|
||||||
|
_domain: null,
|
||||||
|
_host: null,
|
||||||
|
_hostname: null,
|
||||||
|
_uri: message.uri,
|
||||||
|
match: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
username: message.username,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns a cipher view assigned to an existing folder id", () => {
|
||||||
|
const folderId = "folder-id";
|
||||||
|
const message: AddLoginQueueMessage = {
|
||||||
|
type: "add",
|
||||||
|
username: "test",
|
||||||
|
password: "password",
|
||||||
|
uri: "https://example.com",
|
||||||
|
domain: "example.com",
|
||||||
|
tab: createChromeTabMock(),
|
||||||
|
expires: new Date(),
|
||||||
|
wasVaultLocked: false,
|
||||||
|
};
|
||||||
|
const cipherView = notificationBackground["convertAddLoginQueueMessageToCipherView"](
|
||||||
|
message,
|
||||||
|
folderId,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(cipherView.folderId).toEqual(folderId);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,26 +11,27 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
|||||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||||
|
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
||||||
|
|
||||||
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window";
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service";
|
import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service";
|
||||||
import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window";
|
import { openAddEditVaultItemPopout } from "../../vault/popup/utils/vault-popout-window";
|
||||||
import { NOTIFICATION_BAR_LIFESPAN_MS } from "../constants";
|
import { NOTIFICATION_BAR_LIFESPAN_MS } from "../constants";
|
||||||
import AddChangePasswordQueueMessage from "../notification/models/add-change-password-queue-message";
|
import { NotificationQueueMessageType } from "../enums/notification-queue-message-type.enum";
|
||||||
import AddLoginQueueMessage from "../notification/models/add-login-queue-message";
|
|
||||||
import AddLoginRuntimeMessage from "../notification/models/add-login-runtime-message";
|
|
||||||
import AddRequestFilelessImportQueueMessage from "../notification/models/add-request-fileless-import-queue-message";
|
|
||||||
import AddUnlockVaultQueueMessage from "../notification/models/add-unlock-vault-queue-message";
|
|
||||||
import ChangePasswordRuntimeMessage from "../notification/models/change-password-runtime-message";
|
|
||||||
import LockedVaultPendingNotificationsItem from "../notification/models/locked-vault-pending-notifications-item";
|
|
||||||
import {
|
|
||||||
NotificationQueueMessageType,
|
|
||||||
NotificationTypes,
|
|
||||||
} from "../notification/models/notification-queue-message-type";
|
|
||||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||||
|
|
||||||
import { NotificationQueueMessageItem } from "./abstractions/notification.background";
|
import {
|
||||||
|
AddChangePasswordQueueMessage,
|
||||||
|
AddLoginQueueMessage,
|
||||||
|
AddRequestFilelessImportQueueMessage,
|
||||||
|
AddUnlockVaultQueueMessage,
|
||||||
|
ChangePasswordMessageData,
|
||||||
|
AddLoginMessageData,
|
||||||
|
NotificationQueueMessageItem,
|
||||||
|
LockedVaultPendingNotificationsData,
|
||||||
|
} from "./abstractions/notification.background";
|
||||||
|
|
||||||
export default class NotificationBackground {
|
export default class NotificationBackground {
|
||||||
private notificationQueue: NotificationQueueMessageItem[] = [];
|
private notificationQueue: NotificationQueueMessageItem[] = [];
|
||||||
@@ -89,9 +90,9 @@ export default class NotificationBackground {
|
|||||||
case "bgAddSave":
|
case "bgAddSave":
|
||||||
case "bgChangeSave":
|
case "bgChangeSave":
|
||||||
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
||||||
const retryMessage: LockedVaultPendingNotificationsItem = {
|
const retryMessage: LockedVaultPendingNotificationsData = {
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: {
|
message: {
|
||||||
command: msg,
|
command: msg,
|
||||||
},
|
},
|
||||||
sender: sender,
|
sender: sender,
|
||||||
@@ -188,10 +189,7 @@ export default class NotificationBackground {
|
|||||||
notificationQueueMessage: NotificationQueueMessageItem,
|
notificationQueueMessage: NotificationQueueMessageItem,
|
||||||
) {
|
) {
|
||||||
const notificationType = notificationQueueMessage.type;
|
const notificationType = notificationQueueMessage.type;
|
||||||
const webVaultURL =
|
const webVaultURL = this.environmentService.getWebVaultUrl();
|
||||||
notificationType !== NotificationQueueMessageType.UnlockVault
|
|
||||||
? this.environmentService.getWebVaultUrl()
|
|
||||||
: null;
|
|
||||||
const typeData: Record<string, any> = {
|
const typeData: Record<string, any> = {
|
||||||
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
isVaultLocked: notificationQueueMessage.wasVaultLocked,
|
||||||
theme: await this.getCurrentTheme(),
|
theme: await this.getCurrentTheme(),
|
||||||
@@ -210,7 +208,7 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await BrowserApi.tabSendMessageData(tab, "openNotificationBar", {
|
await BrowserApi.tabSendMessageData(tab, "openNotificationBar", {
|
||||||
type: NotificationTypes[notificationType],
|
type: notificationType,
|
||||||
typeData,
|
typeData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -235,7 +233,7 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async addLogin(loginInfo: AddLoginRuntimeMessage, tab: chrome.tabs.Tab) {
|
private async addLogin(loginInfo: AddLoginMessageData, tab: chrome.tabs.Tab) {
|
||||||
const authStatus = await this.authService.getAuthStatus();
|
const authStatus = await this.authService.getAuthStatus();
|
||||||
if (authStatus === AuthenticationStatus.LoggedOut) {
|
if (authStatus === AuthenticationStatus.LoggedOut) {
|
||||||
return;
|
return;
|
||||||
@@ -292,7 +290,7 @@ export default class NotificationBackground {
|
|||||||
|
|
||||||
private async pushAddLoginToQueue(
|
private async pushAddLoginToQueue(
|
||||||
loginDomain: string,
|
loginDomain: string,
|
||||||
loginInfo: AddLoginRuntimeMessage,
|
loginInfo: AddLoginMessageData,
|
||||||
tab: chrome.tabs.Tab,
|
tab: chrome.tabs.Tab,
|
||||||
isVaultLocked = false,
|
isVaultLocked = false,
|
||||||
) {
|
) {
|
||||||
@@ -312,7 +310,7 @@ export default class NotificationBackground {
|
|||||||
await this.checkNotificationQueue(tab);
|
await this.checkNotificationQueue(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async changedPassword(changeData: ChangePasswordRuntimeMessage, tab: chrome.tabs.Tab) {
|
private async changedPassword(changeData: ChangePasswordMessageData, tab: chrome.tabs.Tab) {
|
||||||
const loginDomain = Utils.getDomain(changeData.url);
|
const loginDomain = Utils.getDomain(changeData.url);
|
||||||
if (loginDomain == null) {
|
if (loginDomain == null) {
|
||||||
return;
|
return;
|
||||||
@@ -458,7 +456,11 @@ export default class NotificationBackground {
|
|||||||
private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) {
|
private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) {
|
||||||
for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
|
for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
|
||||||
const queueMessage = this.notificationQueue[i];
|
const queueMessage = this.notificationQueue[i];
|
||||||
if (queueMessage.tab.id !== tab.id || !(queueMessage.type in NotificationQueueMessageType)) {
|
if (
|
||||||
|
queueMessage.tab.id !== tab.id ||
|
||||||
|
(queueMessage.type !== NotificationQueueMessageType.AddLogin &&
|
||||||
|
queueMessage.type !== NotificationQueueMessageType.ChangePassword)
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +496,7 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
folderId = (await this.folderExists(folderId)) ? folderId : null;
|
folderId = (await this.folderExists(folderId)) ? folderId : null;
|
||||||
const newCipher = AddLoginQueueMessage.toCipherView(queueMessage, folderId);
|
const newCipher = this.convertAddLoginQueueMessageToCipherView(queueMessage, folderId);
|
||||||
|
|
||||||
if (edit) {
|
if (edit) {
|
||||||
await this.editItem(newCipher, tab);
|
await this.editItem(newCipher, tab);
|
||||||
@@ -599,10 +601,10 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async handleUnlockCompleted(
|
private async handleUnlockCompleted(
|
||||||
messageData: LockedVaultPendingNotificationsItem,
|
messageData: LockedVaultPendingNotificationsData,
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (messageData.commandToRetry.msg.command === "autofill_login") {
|
if (messageData.commandToRetry.message.command === "autofill_login") {
|
||||||
await BrowserApi.tabSendMessageData(sender.tab, "closeNotificationBar");
|
await BrowserApi.tabSendMessageData(sender.tab, "closeNotificationBar");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,8 +613,36 @@ export default class NotificationBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.processMessage(
|
await this.processMessage(
|
||||||
messageData.commandToRetry.msg.command,
|
messageData.commandToRetry.message.command,
|
||||||
messageData.commandToRetry.sender,
|
messageData.commandToRetry.sender,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts a login queue message and converts it into a
|
||||||
|
* login uri view, login view, and cipher view.
|
||||||
|
*
|
||||||
|
* @param message - The message to convert to a cipher view
|
||||||
|
* @param folderId - The folder to add the cipher to
|
||||||
|
*/
|
||||||
|
private convertAddLoginQueueMessageToCipherView(
|
||||||
|
message: AddLoginQueueMessage,
|
||||||
|
folderId?: string,
|
||||||
|
): CipherView {
|
||||||
|
const uriView = new LoginUriView();
|
||||||
|
uriView.uri = message.uri;
|
||||||
|
|
||||||
|
const loginView = new LoginView();
|
||||||
|
loginView.uris = [uriView];
|
||||||
|
loginView.username = message.username;
|
||||||
|
loginView.password = message.password;
|
||||||
|
|
||||||
|
const cipherView = new CipherView();
|
||||||
|
cipherView.name = (Utils.getHostname(message.uri) || message.domain).replace(/^www\./, "");
|
||||||
|
cipherView.folderId = folderId;
|
||||||
|
cipherView.type = CipherType.Login;
|
||||||
|
cipherView.login = loginView;
|
||||||
|
|
||||||
|
return cipherView;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -911,7 +911,7 @@ describe("OverlayBackground", () => {
|
|||||||
const message = {
|
const message = {
|
||||||
command: "unlockCompleted",
|
command: "unlockCompleted",
|
||||||
data: {
|
data: {
|
||||||
commandToRetry: { msg: { command: "" } },
|
commandToRetry: { message: { command: "" } },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -927,7 +927,7 @@ describe("OverlayBackground", () => {
|
|||||||
const message = {
|
const message = {
|
||||||
command: "unlockCompleted",
|
command: "unlockCompleted",
|
||||||
data: {
|
data: {
|
||||||
commandToRetry: { msg: { command: "openAutofillOverlay" } },
|
commandToRetry: { message: { command: "openAutofillOverlay" } },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
jest.spyOn(BrowserApi, "getTabFromCurrentWindowId").mockResolvedValueOnce(sender.tab);
|
jest.spyOn(BrowserApi, "getTabFromCurrentWindowId").mockResolvedValueOnce(sender.tab);
|
||||||
@@ -1184,7 +1184,7 @@ describe("OverlayBackground", () => {
|
|||||||
"addToLockedVaultPendingNotifications",
|
"addToLockedVaultPendingNotifications",
|
||||||
{
|
{
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: { command: "openAutofillOverlay" },
|
message: { command: "openAutofillOverlay" },
|
||||||
sender: listPortSpy.sender,
|
sender: listPortSpy.sender,
|
||||||
},
|
},
|
||||||
target: "overlay.background",
|
target: "overlay.background",
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ import {
|
|||||||
openAddEditVaultItemPopout,
|
openAddEditVaultItemPopout,
|
||||||
} from "../../vault/popup/utils/vault-popout-window";
|
} from "../../vault/popup/utils/vault-popout-window";
|
||||||
import { SHOW_AUTOFILL_BUTTON } from "../constants";
|
import { SHOW_AUTOFILL_BUTTON } from "../constants";
|
||||||
import LockedVaultPendingNotificationsItem from "../notification/models/locked-vault-pending-notifications-item";
|
|
||||||
import { AutofillService, PageDetail } from "../services/abstractions/autofill.service";
|
import { AutofillService, PageDetail } from "../services/abstractions/autofill.service";
|
||||||
import { AutofillOverlayElement, AutofillOverlayPort } from "../utils/autofill-overlay.enum";
|
import { AutofillOverlayElement, AutofillOverlayPort } from "../utils/autofill-overlay.enum";
|
||||||
|
|
||||||
|
import { LockedVaultPendingNotificationsData } from "./abstractions/notification.background";
|
||||||
import {
|
import {
|
||||||
FocusedFieldData,
|
FocusedFieldData,
|
||||||
OverlayBackgroundExtensionMessageHandlers,
|
OverlayBackgroundExtensionMessageHandlers,
|
||||||
@@ -520,8 +520,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
const { sender } = port;
|
const { sender } = port;
|
||||||
|
|
||||||
this.closeOverlay(port);
|
this.closeOverlay(port);
|
||||||
const retryMessage: LockedVaultPendingNotificationsItem = {
|
const retryMessage: LockedVaultPendingNotificationsData = {
|
||||||
commandToRetry: { msg: { command: "openAutofillOverlay" }, sender },
|
commandToRetry: { message: { command: "openAutofillOverlay" }, sender },
|
||||||
target: "overlay.background",
|
target: "overlay.background",
|
||||||
};
|
};
|
||||||
await BrowserApi.tabSendMessageData(
|
await BrowserApi.tabSendMessageData(
|
||||||
@@ -569,7 +569,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
private async unlockCompleted(message: OverlayBackgroundExtensionMessage) {
|
private async unlockCompleted(message: OverlayBackgroundExtensionMessage) {
|
||||||
await this.getAuthStatus();
|
await this.getAuthStatus();
|
||||||
|
|
||||||
if (message.data?.commandToRetry?.msg?.command === "openAutofillOverlay") {
|
if (message.data?.commandToRetry?.message?.command === "openAutofillOverlay") {
|
||||||
await this.openOverlay(true);
|
await this.openOverlay(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
openAddEditVaultItemPopout,
|
openAddEditVaultItemPopout,
|
||||||
openVaultItemPasswordRepromptPopout,
|
openVaultItemPasswordRepromptPopout,
|
||||||
} from "../../vault/popup/utils/vault-popout-window";
|
} from "../../vault/popup/utils/vault-popout-window";
|
||||||
|
import { LockedVaultPendingNotificationsData } from "../background/abstractions/notification.background";
|
||||||
import { autofillServiceFactory } from "../background/service_factories/autofill-service.factory";
|
import { autofillServiceFactory } from "../background/service_factories/autofill-service.factory";
|
||||||
import { copyToClipboard, GeneratePasswordToClipboardCommand } from "../clipboard";
|
import { copyToClipboard, GeneratePasswordToClipboardCommand } from "../clipboard";
|
||||||
import { AutofillTabCommand } from "../commands/autofill-tab-command";
|
import { AutofillTabCommand } from "../commands/autofill-tab-command";
|
||||||
@@ -50,7 +51,6 @@ import {
|
|||||||
GENERATE_PASSWORD_ID,
|
GENERATE_PASSWORD_ID,
|
||||||
NOOP_COMMAND_SUFFIX,
|
NOOP_COMMAND_SUFFIX,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import LockedVaultPendingNotificationsItem from "../notification/models/locked-vault-pending-notifications-item";
|
|
||||||
import { AutofillCipherTypeId } from "../types";
|
import { AutofillCipherTypeId } from "../types";
|
||||||
|
|
||||||
export type CopyToClipboardOptions = { text: string; tab: chrome.tabs.Tab };
|
export type CopyToClipboardOptions = { text: string; tab: chrome.tabs.Tab };
|
||||||
@@ -138,7 +138,7 @@ export class ContextMenuClickedHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async messageListener(
|
static async messageListener(
|
||||||
message: { command: string; data: LockedVaultPendingNotificationsItem },
|
message: { command: string; data: LockedVaultPendingNotificationsData },
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
cachedServices: CachedServices,
|
cachedServices: CachedServices,
|
||||||
) {
|
) {
|
||||||
@@ -151,7 +151,7 @@ export class ContextMenuClickedHandler {
|
|||||||
|
|
||||||
const contextMenuClickedHandler = await ContextMenuClickedHandler.mv3Create(cachedServices);
|
const contextMenuClickedHandler = await ContextMenuClickedHandler.mv3Create(cachedServices);
|
||||||
await contextMenuClickedHandler.run(
|
await contextMenuClickedHandler.run(
|
||||||
message.data.commandToRetry.msg.data,
|
message.data.commandToRetry.message.contextMenuOnClickData,
|
||||||
message.data.commandToRetry.sender.tab,
|
message.data.commandToRetry.sender.tab,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -179,9 +179,9 @@ export class ContextMenuClickedHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
||||||
const retryMessage: LockedVaultPendingNotificationsItem = {
|
const retryMessage: LockedVaultPendingNotificationsData = {
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: { command: NOOP_COMMAND_SUFFIX, data: info },
|
message: { command: NOOP_COMMAND_SUFFIX, contextMenuOnClickData: info },
|
||||||
sender: { tab: tab },
|
sender: { tab: tab },
|
||||||
},
|
},
|
||||||
target: "contextmenus.background",
|
target: "contextmenus.background",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import {
|
||||||
|
AddLoginMessageData,
|
||||||
|
ChangePasswordMessageData,
|
||||||
|
} from "../background/abstractions/notification.background";
|
||||||
import AutofillField from "../models/autofill-field";
|
import AutofillField from "../models/autofill-field";
|
||||||
import { WatchedForm } from "../models/watched-form";
|
import { WatchedForm } from "../models/watched-form";
|
||||||
import AddLoginRuntimeMessage from "../notification/models/add-login-runtime-message";
|
|
||||||
import ChangePasswordRuntimeMessage from "../notification/models/change-password-runtime-message";
|
|
||||||
import { FormData } from "../services/abstractions/autofill.service";
|
import { FormData } from "../services/abstractions/autofill.service";
|
||||||
import { GlobalSettings, UserSettings } from "../types";
|
import { GlobalSettings, UserSettings } from "../types";
|
||||||
import { getFromLocalStorage, setupExtensionDisconnectAction } from "../utils";
|
import { getFromLocalStorage, setupExtensionDisconnectAction } from "../utils";
|
||||||
@@ -611,7 +613,7 @@ async function loadNotificationBar() {
|
|||||||
watchedForms[i].passwordEl != null
|
watchedForms[i].passwordEl != null
|
||||||
) {
|
) {
|
||||||
// Create a login object from the form data
|
// Create a login object from the form data
|
||||||
const login: AddLoginRuntimeMessage = {
|
const login: AddLoginMessageData = {
|
||||||
username: watchedForms[i].usernameEl.value,
|
username: watchedForms[i].usernameEl.value,
|
||||||
password: watchedForms[i].passwordEl.value,
|
password: watchedForms[i].passwordEl.value,
|
||||||
url: document.URL,
|
url: document.URL,
|
||||||
@@ -624,7 +626,7 @@ async function loadNotificationBar() {
|
|||||||
processedForm(form);
|
processedForm(form);
|
||||||
sendPlatformMessage({
|
sendPlatformMessage({
|
||||||
command: "bgAddLogin",
|
command: "bgAddLogin",
|
||||||
login: login,
|
login,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
@@ -694,15 +696,12 @@ async function loadNotificationBar() {
|
|||||||
|
|
||||||
// Send a message to the `notification.background.ts` background script to notify the user that their password has changed
|
// Send a message to the `notification.background.ts` background script to notify the user that their password has changed
|
||||||
// which eventually calls the `processMessage(...)` method in this script with command `openNotificationBar`
|
// which eventually calls the `processMessage(...)` method in this script with command `openNotificationBar`
|
||||||
const changePasswordRuntimeMessage: ChangePasswordRuntimeMessage = {
|
const data: ChangePasswordMessageData = {
|
||||||
newPassword: newPass,
|
newPassword: newPass,
|
||||||
currentPassword: curPass,
|
currentPassword: curPass,
|
||||||
url: document.URL,
|
url: document.URL,
|
||||||
};
|
};
|
||||||
sendPlatformMessage({
|
sendPlatformMessage({ command: "bgChangedPassword", data });
|
||||||
command: "bgChangedPassword",
|
|
||||||
data: changePasswordRuntimeMessage,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const NotificationQueueMessageType = {
|
||||||
|
AddLogin: "add",
|
||||||
|
ChangePassword: "change",
|
||||||
|
UnlockVault: "unlock",
|
||||||
|
RequestFilelessImport: "fileless-import",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type NotificationQueueMessageTypes =
|
||||||
|
(typeof NotificationQueueMessageType)[keyof typeof NotificationQueueMessageType];
|
||||||
|
|
||||||
|
export { NotificationQueueMessageType, NotificationQueueMessageTypes };
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import NotificationQueueMessage from "./notification-queue-message";
|
|
||||||
import { NotificationQueueMessageType } from "./notification-queue-message-type";
|
|
||||||
|
|
||||||
export default class AddChangePasswordQueueMessage extends NotificationQueueMessage {
|
|
||||||
type: NotificationQueueMessageType.ChangePassword;
|
|
||||||
cipherId: string;
|
|
||||||
newPassword: string;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|
||||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
|
||||||
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
|
|
||||||
|
|
||||||
import NotificationQueueMessage from "./notification-queue-message";
|
|
||||||
import { NotificationQueueMessageType } from "./notification-queue-message-type";
|
|
||||||
|
|
||||||
export default class AddLoginQueueMessage extends NotificationQueueMessage {
|
|
||||||
type: NotificationQueueMessageType.AddLogin;
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
uri: string;
|
|
||||||
|
|
||||||
static toCipherView(message: AddLoginQueueMessage, folderId?: string): CipherView {
|
|
||||||
const uriView = new LoginUriView();
|
|
||||||
uriView.uri = message.uri;
|
|
||||||
|
|
||||||
const loginView = new LoginView();
|
|
||||||
loginView.uris = [uriView];
|
|
||||||
loginView.username = message.username;
|
|
||||||
loginView.password = message.password;
|
|
||||||
|
|
||||||
const cipherView = new CipherView();
|
|
||||||
cipherView.name = (Utils.getHostname(message.uri) || message.domain).replace(/^www\./, "");
|
|
||||||
cipherView.folderId = folderId;
|
|
||||||
cipherView.type = CipherType.Login;
|
|
||||||
cipherView.login = loginView;
|
|
||||||
|
|
||||||
return cipherView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default class AddLoginRuntimeMessage {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import NotificationQueueMessage from "./notification-queue-message";
|
|
||||||
import { NotificationQueueMessageType } from "./notification-queue-message-type";
|
|
||||||
|
|
||||||
export default class AddRequestFilelessImportQueueMessage extends NotificationQueueMessage {
|
|
||||||
type: NotificationQueueMessageType.RequestFilelessImport;
|
|
||||||
importType?: string;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import NotificationQueueMessage from "./notification-queue-message";
|
|
||||||
import { NotificationQueueMessageType } from "./notification-queue-message-type";
|
|
||||||
|
|
||||||
export default class AddUnlockVaultQueueMessage extends NotificationQueueMessage {
|
|
||||||
type: NotificationQueueMessageType.UnlockVault;
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export default class ChangePasswordRuntimeMessage {
|
|
||||||
currentPassword: string;
|
|
||||||
newPassword: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
export default class LockedVaultPendingNotificationsItem {
|
|
||||||
commandToRetry: {
|
|
||||||
msg: {
|
|
||||||
command: string;
|
|
||||||
data?: any;
|
|
||||||
};
|
|
||||||
sender: chrome.runtime.MessageSender;
|
|
||||||
};
|
|
||||||
target: string;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
enum NotificationQueueMessageType {
|
|
||||||
AddLogin = 0,
|
|
||||||
ChangePassword = 1,
|
|
||||||
UnlockVault = 2,
|
|
||||||
RequestFilelessImport = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
const NotificationTypes = {
|
|
||||||
[NotificationQueueMessageType.AddLogin]: "add",
|
|
||||||
[NotificationQueueMessageType.ChangePassword]: "change",
|
|
||||||
[NotificationQueueMessageType.UnlockVault]: "unlock",
|
|
||||||
[NotificationQueueMessageType.RequestFilelessImport]: "fileless-import",
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export { NotificationQueueMessageType, NotificationTypes };
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { NotificationQueueMessageType } from "./notification-queue-message-type";
|
|
||||||
|
|
||||||
export default class NotificationQueueMessage {
|
|
||||||
type: NotificationQueueMessageType;
|
|
||||||
domain: string;
|
|
||||||
tab: chrome.tabs.Tab;
|
|
||||||
expires: Date;
|
|
||||||
wasVaultLocked: boolean;
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
|
||||||
import { openUnlockPopout } from "../auth/popup/utils/auth-popout-window";
|
import { openUnlockPopout } from "../auth/popup/utils/auth-popout-window";
|
||||||
import LockedVaultPendingNotificationsItem from "../autofill/notification/models/locked-vault-pending-notifications-item";
|
import { LockedVaultPendingNotificationsData } from "../autofill/background/abstractions/notification.background";
|
||||||
import { BrowserApi } from "../platform/browser/browser-api";
|
import { BrowserApi } from "../platform/browser/browser-api";
|
||||||
|
|
||||||
import MainBackground from "./main.background";
|
import MainBackground from "./main.background";
|
||||||
@@ -28,9 +28,10 @@ export default class CommandsBackground {
|
|||||||
async init() {
|
async init() {
|
||||||
BrowserApi.messageListener("commands.background", (msg: any) => {
|
BrowserApi.messageListener("commands.background", (msg: any) => {
|
||||||
if (msg.command === "unlockCompleted" && msg.data.target === "commands.background") {
|
if (msg.command === "unlockCompleted" && msg.data.target === "commands.background") {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
this.processCommand(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
msg.data.commandToRetry.message.command,
|
||||||
this.processCommand(msg.data.commandToRetry.msg.command, msg.data.commandToRetry.sender);
|
msg.data.commandToRetry.sender,
|
||||||
|
).catch((error) => this.main.logService.error(error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -64,9 +65,7 @@ export default class CommandsBackground {
|
|||||||
const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {};
|
const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {};
|
||||||
const password = await this.passwordGenerationService.generatePassword(options);
|
const password = await this.passwordGenerationService.generatePassword(options);
|
||||||
this.platformUtilsService.copyToClipboard(password, { window: window });
|
this.platformUtilsService.copyToClipboard(password, { window: window });
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
await this.passwordGenerationService.addHistory(password);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.passwordGenerationService.addHistory(password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async autoFillLogin(tab?: chrome.tabs.Tab) {
|
private async autoFillLogin(tab?: chrome.tabs.Tab) {
|
||||||
@@ -79,9 +78,9 @@ export default class CommandsBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
||||||
const retryMessage: LockedVaultPendingNotificationsItem = {
|
const retryMessage: LockedVaultPendingNotificationsData = {
|
||||||
commandToRetry: {
|
commandToRetry: {
|
||||||
msg: { command: "autofill_login" },
|
message: { command: "autofill_login" },
|
||||||
sender: { tab: tab },
|
sender: { tab: tab },
|
||||||
},
|
},
|
||||||
target: "commands.background",
|
target: "commands.background",
|
||||||
@@ -105,8 +104,6 @@ export default class CommandsBackground {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
await this.main.openPopup();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.main.openPopup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
openSsoAuthResultPopout,
|
openSsoAuthResultPopout,
|
||||||
openTwoFactorAuthPopout,
|
openTwoFactorAuthPopout,
|
||||||
} from "../auth/popup/utils/auth-popout-window";
|
} from "../auth/popup/utils/auth-popout-window";
|
||||||
import LockedVaultPendingNotificationsItem from "../autofill/notification/models/locked-vault-pending-notifications-item";
|
import { LockedVaultPendingNotificationsData } from "../autofill/background/abstractions/notification.background";
|
||||||
import { AutofillService } from "../autofill/services/abstractions/autofill.service";
|
import { AutofillService } from "../autofill/services/abstractions/autofill.service";
|
||||||
import { AutofillOverlayVisibility } from "../autofill/utils/autofill-overlay.enum";
|
import { AutofillOverlayVisibility } from "../autofill/utils/autofill-overlay.enum";
|
||||||
import { BrowserApi } from "../platform/browser/browser-api";
|
import { BrowserApi } from "../platform/browser/browser-api";
|
||||||
@@ -29,7 +29,7 @@ export default class RuntimeBackground {
|
|||||||
private autofillTimeout: any;
|
private autofillTimeout: any;
|
||||||
private pageDetailsToAutoFill: any[] = [];
|
private pageDetailsToAutoFill: any[] = [];
|
||||||
private onInstalledReason: string = null;
|
private onInstalledReason: string = null;
|
||||||
private lockedVaultPendingNotifications: LockedVaultPendingNotificationsItem[] = [];
|
private lockedVaultPendingNotifications: LockedVaultPendingNotificationsData[] = [];
|
||||||
private abortManager = new AbortManager();
|
private abortManager = new AbortManager();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -94,7 +94,7 @@ export default class RuntimeBackground {
|
|||||||
switch (msg.command) {
|
switch (msg.command) {
|
||||||
case "loggedIn":
|
case "loggedIn":
|
||||||
case "unlocked": {
|
case "unlocked": {
|
||||||
let item: LockedVaultPendingNotificationsItem;
|
let item: LockedVaultPendingNotificationsData;
|
||||||
|
|
||||||
if (this.lockedVaultPendingNotifications?.length > 0) {
|
if (this.lockedVaultPendingNotifications?.length > 0) {
|
||||||
item = this.lockedVaultPendingNotifications.pop();
|
item = this.lockedVaultPendingNotifications.pop();
|
||||||
|
|||||||
Reference in New Issue
Block a user