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

[PM-17564] Prompt Browser Extension (#13349)

* add browser extension prompt page with initial loading state

* add browser extension icon

* move browser extension prompt to state

* add installation link for error state

* automatically open extension when possible for browser-reprompt-page

* refactor browser tabs query into a standalone method

* add success message state for auto-opening browsers

* Refactor `VaultOnboardingMessages` to `VaultMessages` to be more generic

* add auto-open extension messages to `VaultMessages` enum

* add bitwarden icon

* Add manual error state for firefox users

* add extension prompt routing

* fix incorrect imports

* add mobile screen for browser prompt

* remove comment

* fix typo in code comment

* update key for `checkBwInstalled` method

* add check for safari before attempting to send a message

* break translation for manual opening into two parts
This commit is contained in:
Nick Krantz
2025-02-19 13:00:07 -06:00
committed by GitHub
parent 661ee03698
commit dae4f7b3cc
24 changed files with 869 additions and 32 deletions

View File

@@ -1,6 +1,6 @@
import { mock } from "jest-mock-extended";
import { VaultOnboardingMessages } from "@bitwarden/common/vault/enums/vault-onboarding.enum";
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
import { postWindowMessage, sendMockExtensionMessage } from "../spec/testing-utils";
@@ -34,10 +34,10 @@ describe("ContentMessageHandler", () => {
const mockPostMessage = jest.fn();
window.postMessage = mockPostMessage;
postWindowMessage({ command: VaultOnboardingMessages.checkBwInstalled });
postWindowMessage({ command: VaultMessages.checkBwInstalled });
expect(mockPostMessage).toHaveBeenCalledWith({
command: VaultOnboardingMessages.HasBwInstalled,
command: VaultMessages.HasBwInstalled,
});
});
});

View File

@@ -1,4 +1,4 @@
import { VaultOnboardingMessages } from "@bitwarden/common/vault/enums/vault-onboarding.enum";
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
import {
ContentMessageWindowData,
@@ -26,16 +26,17 @@ const windowMessageHandlers: ContentMessageWindowEventHandlers = {
handleAuthResultMessage(data, referrer),
webAuthnResult: ({ data, referrer }: { data: any; referrer: string }) =>
handleWebAuthnResultMessage(data, referrer),
checkIfBWExtensionInstalled: () => handleExtensionInstallCheck(),
[VaultMessages.checkBwInstalled]: () => handleExtensionInstallCheck(),
duoResult: ({ data, referrer }: { data: any; referrer: string }) =>
handleDuoResultMessage(data, referrer),
[VaultMessages.OpenPopup]: () => handleOpenPopupMessage(),
};
/**
* Handles the post to the web vault showing the extension has been installed
*/
function handleExtensionInstallCheck() {
window.postMessage({ command: VaultOnboardingMessages.HasBwInstalled });
window.postMessage({ command: VaultMessages.HasBwInstalled });
}
/**
@@ -71,6 +72,10 @@ function handleWebAuthnResultMessage(data: ContentMessageWindowData, referrer: s
sendExtensionRuntimeMessage({ command, data: data.data, remember, referrer });
}
function handleOpenPopupMessage() {
sendExtensionRuntimeMessage({ command: VaultMessages.OpenPopup });
}
/**
* Handles the window message event.
*

View File

@@ -1592,13 +1592,16 @@ export default class MainBackground {
}
async openPopup() {
// Chrome APIs cannot open popup
const browserAction = BrowserApi.getBrowserAction();
// TODO: Do we need to open this popup?
if (!this.isSafari) {
if ("openPopup" in browserAction && typeof browserAction.openPopup === "function") {
await browserAction.openPopup();
return;
}
await SafariApp.sendMessageToApp("showPopover", null, true);
if (this.isSafari) {
await SafariApp.sendMessageToApp("showPopover", null, true);
}
}
async reseedStorage() {

View File

@@ -289,7 +289,7 @@ export default class RuntimeBackground {
}
break;
case "openPopup":
await this.main.openPopup();
await this.openPopup();
break;
case "bgUpdateContextMenu":
case "editedCipher":
@@ -405,13 +405,40 @@ export default class RuntimeBackground {
}, 100);
}
/** Returns the browser tabs that have the web vault open */
private async getBwTabs() {
const env = await firstValueFrom(this.environmentService.environment$);
const vaultUrl = env.getWebVaultUrl();
const urlObj = new URL(vaultUrl);
return await BrowserApi.tabsQuery({ url: `${urlObj.href}*` });
}
private async openPopup() {
await this.main.openPopup();
const announcePopupOpen = async () => {
const isOpen = await this.platformUtilsService.isViewOpen();
const tabs = await this.getBwTabs();
if (isOpen && tabs.length > 0) {
// Send message to all vault tabs that the extension has opened
for (const tab of tabs) {
await BrowserApi.executeScriptInTab(tab.id, {
file: "content/send-popup-open-message.js",
runAt: "document_end",
});
}
}
};
// Give the popup a buffer to open
setTimeout(announcePopupOpen, 100);
}
async sendBwInstalledMessageToVault() {
try {
const env = await firstValueFrom(this.environmentService.environment$);
const vaultUrl = env.getWebVaultUrl();
const urlObj = new URL(vaultUrl);
const tabs = await BrowserApi.tabsQuery({ url: `${urlObj.href}*` });
const tabs = await this.getBwTabs();
if (!tabs?.length) {
return;

View File

@@ -1,5 +1,5 @@
import { VaultOnboardingMessages } from "@bitwarden/common/vault/enums/vault-onboarding.enum";
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
(function (globalContext) {
globalContext.postMessage({ command: VaultOnboardingMessages.HasBwInstalled });
globalContext.postMessage({ command: VaultMessages.HasBwInstalled });
})(window);

View File

@@ -0,0 +1,6 @@
import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum";
(function (globalContext) {
// Send a message to the window that the popup opened
globalContext.postMessage({ command: VaultMessages.PopupOpened });
})(window);

View File

@@ -207,6 +207,7 @@ const mainConfig = {
"./src/autofill/deprecated/overlay/pages/list/bootstrap-autofill-overlay-list.deprecated.ts",
"encrypt-worker": "../../libs/common/src/key-management/crypto/services/encrypt.worker.ts",
"content/send-on-installed-message": "./src/vault/content/send-on-installed-message.ts",
"content/send-popup-open-message": "./src/vault/content/send-popup-open-message.ts",
},
optimization: {
minimize: ENV !== "development",