1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-02-24 02:41:54 +01:00

[PM-5189] Implementing the message-connector to ensure we are sending messages without posting a window message

This commit is contained in:
Cesar Gonzalez 2024-04-07 20:35:51 -05:00
parent 3313807acb
commit d6d52e5e5e
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
20 changed files with 182 additions and 91 deletions

View File

@ -12,10 +12,10 @@ type PageDetailsForTab = Record<
>;
type SubFrameOffsetData = {
frameId?: number;
url?: string;
top: number;
left: number;
frameId?: number;
} | null;
type SubFrameOffsetsForTab = Record<
@ -49,9 +49,9 @@ type OverlayBackgroundExtensionMessage = {
forceCloseOverlay?: boolean;
isOverlayHidden?: boolean;
setTransparentOverlay?: boolean;
data?: LockedVaultPendingNotificationsData;
isFieldCurrentlyFocused?: boolean;
isCurrentlyFilling?: boolean;
data?: LockedVaultPendingNotificationsData;
} & OverlayAddNewItemMessage;
type OverlayPortMessage = {
@ -132,6 +132,7 @@ type OverlayButtonPortMessageHandlers = {
forceCloseAutofillOverlay: ({ port }: PortConnectionParam) => void;
overlayPageBlurred: () => void;
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
getPageColorScheme: () => void;
};
type OverlayListPortMessageHandlers = {
@ -144,6 +145,7 @@ type OverlayListPortMessageHandlers = {
addNewVaultItem: ({ port }: PortConnectionParam) => void;
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
updateAutofillOverlayListHeight: ({ message, port }: PortOnMessageHandlerParams) => void;
};
interface OverlayBackground {

View File

@ -95,6 +95,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.closeOverlay(port.sender, { forceCloseOverlay: true }),
overlayPageBlurred: () => this.checkOverlayListFocused(),
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
getPageColorScheme: () => {
this.overlayButtonPort?.postMessage({
command: "getPageColorScheme",
});
},
};
private readonly overlayListPortMessageHandlers: OverlayListPortMessageHandlers = {
checkAutofillOverlayButtonFocused: () => this.checkOverlayButtonFocused(),
@ -106,6 +111,12 @@ class OverlayBackground implements OverlayBackgroundInterface {
addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port),
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
updateAutofillOverlayListHeight: ({ message }) => {
this.overlayListPort?.postMessage({
command: "updateIframePosition",
styles: message.styles,
});
},
};
constructor(
@ -832,7 +843,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
await BrowserApi.sendMessage("inlineAutofillMenuRefreshAddEditCipher");
}
private updateIsFieldCurrentlyFocused({ message }: OverlayBackgroundExtensionMessage) {
private updateIsFieldCurrentlyFocused(message: OverlayBackgroundExtensionMessage) {
this.isFieldCurrentlyFocused = message.isFieldCurrentlyFocused;
}
@ -910,6 +921,14 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param port - The port that connected to the extension background
*/
private handlePortOnConnect = async (port: chrome.runtime.Port) => {
const isOverlayListMessageConnector = port.name === AutofillOverlayPort.ListMessageConnector;
const isOverlayButtonMessageConnector =
port.name === AutofillOverlayPort.ButtonMessageConnector;
if (isOverlayListMessageConnector || isOverlayButtonMessageConnector) {
port.onMessage.addListener(this.handleOverlayElementPortMessage);
return;
}
const isOverlayListPort = port.name === AutofillOverlayPort.List;
const isOverlayButtonPort = port.name === AutofillOverlayPort.Button;
@ -923,7 +942,6 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.overlayButtonPort = port;
}
port.onMessage.addListener(this.handleOverlayElementPortMessage);
port.onDisconnect.addListener(this.handlePortOnDisconnect);
port.postMessage({
command: `initAutofillOverlay${isOverlayListPort ? "List" : "Button"}`,
@ -932,6 +950,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
translations: this.getTranslations(),
ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null,
messageConnectorUrl: chrome.runtime.getURL("overlay/message-connector.html"),
});
void this.updateOverlayPosition(
{
@ -956,11 +975,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
const command = message?.command;
let handler: CallableFunction | undefined;
if (port.name === AutofillOverlayPort.Button) {
if (port.name === AutofillOverlayPort.ButtonMessageConnector) {
handler = this.overlayButtonPortMessageHandlers[command];
}
if (port.name === AutofillOverlayPort.List) {
if (port.name === AutofillOverlayPort.ListMessageConnector) {
handler = this.overlayListPortMessageHandlers[command];
}

View File

@ -24,7 +24,7 @@ const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers
globalThis.addEventListener("load", load);
function load() {
setupWindowMessageListener();
postMessageToParent({ command: "initNotificationBar" });
postMessageToConnector({ command: "initNotificationBar" });
}
function initNotificationBar(message: NotificationBarWindowMessage) {
@ -392,6 +392,6 @@ function setNotificationBarTheme() {
document.documentElement.classList.add(`theme_${theme}`);
}
function postMessageToParent(message: NotificationBarWindowMessage) {
function postMessageToConnector(message: NotificationBarWindowMessage) {
globalThis.parent.postMessage(message, windowMessageOrigin || "*");
}

View File

@ -7,6 +7,7 @@ type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: Authenticati
type InitAutofillOverlayButtonMessage = UpdateAuthStatusMessage & {
styleSheetUrl: string;
translations: Record<string, string>;
messageConnectorUrl: string;
};
type OverlayButtonWindowMessageHandlers = {

View File

@ -7,7 +7,6 @@ type AutofillOverlayIframeExtensionMessage = {
type AutofillOverlayIframeWindowMessageHandlers = {
[key: string]: CallableFunction;
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
getPageColorScheme: () => void;
};
type AutofillOverlayIframeExtensionMessageParam = {
@ -19,6 +18,7 @@ type BackgroundPortMessageHandlers = {
initAutofillOverlayList: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
updateIframePosition: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
updateOverlayHidden: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
getPageColorScheme: () => void;
};
interface AutofillOverlayIframeService {

View File

@ -14,6 +14,7 @@ type InitAutofillOverlayListMessage = OverlayListMessage & {
theme: string;
translations: Record<string, string>;
ciphers?: OverlayCipherData[];
messageConnectorUrl: string;
};
type OverlayListWindowMessageHandlers = {

View File

@ -70,13 +70,13 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
* unobserve the body element to ensure the mutation observer no
* longer triggers.
*/
private removeInlineMenu = (message: any) => {
if (message.overlayElement === AutofillOverlayElement.Button) {
private removeInlineMenu = (message?: AutofillExtensionMessage) => {
if (message?.overlayElement === AutofillOverlayElement.Button) {
this.removeInlineMenuButton();
return;
}
if (message.overlayElement === AutofillOverlayElement.List) {
if (message?.overlayElement === AutofillOverlayElement.List) {
this.removeInlineMenuList();
return;
}
@ -408,7 +408,7 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
clearTimeout(this.mutationObserverIterationsResetTimeout);
this.mutationObserverIterations = 0;
void this.sendExtensionMessage("blurMostRecentOverlayField");
this.removeInlineMenu({ forceClose: true });
this.removeInlineMenu();
return true;
}
@ -417,6 +417,6 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
}
destroy() {
this.documentElementMutationObserver?.disconnect();
this.removeInlineMenu({ forceClose: true });
this.removeInlineMenu();
}
}

View File

@ -1,17 +1,15 @@
import { EVENTS } from "@bitwarden/common/autofill/constants";
import { ThemeType } from "@bitwarden/common/platform/enums";
import { setElementStyles } from "../../utils";
import { sendExtensionMessage, setElementStyles } from "../../utils";
import {
BackgroundPortMessageHandlers,
AutofillOverlayIframeService as AutofillOverlayIframeServiceInterface,
AutofillOverlayIframeExtensionMessage,
AutofillOverlayIframeWindowMessageHandlers,
} from "../abstractions/autofill-overlay-iframe.service";
class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterface {
private port: chrome.runtime.Port | null = null;
private extensionOriginsSet: Set<string>;
private iframeMutationObserver: MutationObserver;
private iframe: HTMLIFrameElement;
private ariaAlertElement: HTMLDivElement;
@ -42,15 +40,11 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
private foreignMutationsCount = 0;
private mutationObserverIterations = 0;
private mutationObserverIterationsResetTimeout: number | NodeJS.Timeout;
private readonly windowMessageHandlers: AutofillOverlayIframeWindowMessageHandlers = {
updateAutofillOverlayListHeight: (message) =>
this.updateElementStyles(this.iframe, message.styles),
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
};
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
updateIframePosition: ({ message }) => this.updateIframePosition(message.styles),
updateOverlayHidden: ({ message }) => this.updateElementStyles(this.iframe, message.styles),
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
};
constructor(
@ -58,11 +52,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
private portName: string,
private shadow: ShadowRoot,
) {
this.extensionOriginsSet = new Set([
chrome.runtime.getURL("").slice(0, -1).toLowerCase(), // Remove the trailing slash and normalize the extension url to lowercase
"null",
]);
this.iframeMutationObserver = new MutationObserver(this.handleMutations);
}
@ -134,7 +123,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
this.port = chrome.runtime.connect({ name: this.portName });
this.port.onDisconnect.addListener(this.handlePortDisconnect);
this.port.onMessage.addListener(this.handlePortMessage);
globalThis.addEventListener(EVENTS.MESSAGE, this.handleWindowMessage);
this.announceAriaAlert();
};
@ -168,7 +156,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
}
this.updateElementStyles(this.iframe, { opacity: "0", height: "0px", display: "block" });
globalThis.removeEventListener("message", this.handleWindowMessage);
this.unobserveIframe();
this.port?.onMessage.removeListener(this.handlePortMessage);
this.port?.onDisconnect.removeListener(this.handlePortDisconnect);
@ -265,30 +252,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
);
}
/**
* Handles messages sent from the iframe. If the message does not have a
* specified handler set, it passes the message to the background script.
*
* @param event - The message event
*/
private handleWindowMessage = (event: MessageEvent) => {
if (
!this.port ||
event.source !== this.iframe.contentWindow ||
!this.isFromExtensionOrigin(event.origin.toLowerCase())
) {
return;
}
const message = event.data;
if (this.windowMessageHandlers[message.command]) {
this.windowMessageHandlers[message.command](message);
return;
}
this.port.postMessage(event.data);
};
/**
* Accepts an element and updates the styles for that element. This method
* will also unobserve the element if it is the iframe element. This is
@ -311,17 +274,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
this.observeIframe();
}
/**
* Chrome returns null for any sandboxed iframe sources.
* Firefox references the extension URI as its origin.
* Any other origin value is a security risk.
*
* @param messageOrigin - The origin of the window message
*/
private isFromExtensionOrigin(messageOrigin: string): boolean {
return this.extensionOriginsSet.has(messageOrigin);
}
/**
* Handles mutations to the iframe element. The ensures that the iframe
* element's styles are not modified by a third party source.
@ -351,6 +303,10 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
}
};
private forceCloseAutofillOverlay() {
void sendExtensionMessage("closeAutofillOverlay", { forceClose: true });
}
/**
* Handles mutations to the iframe element's attributes. This ensures that
* the iframe element's attributes are not modified by a third party source.
@ -366,7 +322,7 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
}
if (this.foreignMutationsCount >= 10) {
this.port?.postMessage({ command: "forceCloseAutofillOverlay" });
this.forceCloseAutofillOverlay();
break;
}
@ -421,7 +377,7 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
if (this.mutationObserverIterations > 20) {
clearTimeout(this.mutationObserverIterationsResetTimeout);
resetCounters();
this.port?.postMessage({ command: "forceCloseAutofillOverlay" });
this.forceCloseAutofillOverlay();
return true;
}

View File

@ -46,15 +46,20 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
* @param authStatus - The authentication status of the user
* @param styleSheetUrl - The URL of the stylesheet to apply to the page
* @param translations - The translations to apply to the page
* @private
* @param messageConnectorUrl - The URL of the message connector to use
*/
private async initAutofillOverlayButton({
authStatus,
styleSheetUrl,
translations,
messageConnectorUrl,
}: InitAutofillOverlayButtonMessage) {
const linkElement = this.initOverlayPage("button", styleSheetUrl, translations);
const linkElement = await this.initOverlayPage(
"button",
styleSheetUrl,
translations,
messageConnectorUrl,
);
this.buttonElement.tabIndex = -1;
this.buttonElement.type = "button";
this.buttonElement.classList.add("overlay-button");
@ -63,7 +68,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
this.getTranslation("toggleBitwardenVaultOverlay"),
);
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
this.postMessageToParent({ command: "getPageColorScheme" });
this.postMessageToConnector({ command: "getPageColorScheme" });
this.updateAuthStatus(authStatus);
@ -103,7 +108,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
* parent window indicating that the button was clicked.
*/
private handleButtonElementClick = () => {
this.postMessageToParent({ command: "overlayButtonClicked" });
this.postMessageToConnector({ command: "overlayButtonClicked" });
};
/**
@ -115,7 +120,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
return;
}
this.postMessageToParent({ command: "closeAutofillOverlay" });
this.postMessageToConnector({ command: "closeAutofillOverlay" });
}
}

View File

@ -44,6 +44,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
* @param theme - The theme to use for the overlay list.
* @param authStatus - The current authentication status.
* @param ciphers - The ciphers to display in the overlay list.
* @param messageConnectorUrl - The URL of the message connector to use.
*/
private async initAutofillOverlayList({
translations,
@ -51,8 +52,14 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
theme,
authStatus,
ciphers,
messageConnectorUrl,
}: InitAutofillOverlayListMessage) {
const linkElement = this.initOverlayPage("button", styleSheetUrl, translations);
const linkElement = await this.initOverlayPage(
"list",
styleSheetUrl,
translations,
messageConnectorUrl,
);
const themeClass = `theme_${theme}`;
globalThis.document.documentElement.classList.add(themeClass);
@ -105,7 +112,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
* Sends a message to the parent window to unlock the vault.
*/
private handleUnlockButtonClick = () => {
this.postMessageToParent({ command: "unlockVault" });
this.postMessageToConnector({ command: "unlockVault" });
};
/**
@ -169,7 +176,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
* Sends a message to the parent window to add a new vault item.
*/
private handeNewItemButtonClick = () => {
this.postMessageToParent({ command: "addNewVaultItem" });
this.postMessageToConnector({ command: "addNewVaultItem" });
};
/**
@ -276,7 +283,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
private handleFillCipherClickEvent = (cipher: OverlayCipherData) => {
return this.useEventHandlersMemo(
() =>
this.postMessageToParent({
this.postMessageToConnector({
command: "fillSelectedListItem",
overlayCipherId: cipher.id,
}),
@ -341,7 +348,8 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
*/
private handleViewCipherClickEvent = (cipher: OverlayCipherData) => {
return this.useEventHandlersMemo(
() => this.postMessageToParent({ command: "viewSelectedCipher", overlayCipherId: cipher.id }),
() =>
this.postMessageToConnector({ command: "viewSelectedCipher", overlayCipherId: cipher.id }),
`${cipher.id}-view-cipher-button-click-handler`,
);
};
@ -476,7 +484,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
return;
}
this.postMessageToParent({ command: "checkAutofillOverlayButtonFocused" });
this.postMessageToConnector({ command: "checkAutofillOverlayButtonFocused" });
}
/**
@ -533,7 +541,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
}
const { height } = entry.contentRect;
this.postMessageToParent({
this.postMessageToConnector({
command: "updateAutofillOverlayListHeight",
styles: { height: `${height}px` },
});

View File

@ -0,0 +1,3 @@
import { AutofillOverlayMessageConnector } from "./message-connector";
(() => new AutofillOverlayMessageConnector())();

View File

@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<title>Autofill overlay message connector</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="color-scheme" content="normal" />
</head>
<body></body>
</html>

View File

@ -0,0 +1,46 @@
export class AutofillOverlayMessageConnector {
private extensionOriginsSet: Set<string>;
private port: chrome.runtime.Port | null = null;
constructor() {
globalThis.addEventListener("message", this.handleWindowMessage);
this.extensionOriginsSet = new Set([
chrome.runtime.getURL("").slice(0, -1).toLowerCase(), // Remove the trailing slash and normalize the extension url to lowercase
"null",
]);
}
private handleWindowMessage = (event: MessageEvent) => {
if (
event.source !== globalThis.parent ||
!this.isFromExtensionOrigin(event.origin.toLowerCase())
) {
return;
}
const message = event.data;
if (this.port) {
this.port.postMessage(message);
return;
}
if (message.command !== "initAutofillOverlayPort") {
return;
}
this.port = chrome.runtime.connect({ name: message.portName });
};
/**
* Chrome returns null for any sandboxed iframe sources.
* Firefox references the extension URI as its origin.
* Any other origin value is a security risk.
*
* @param messageOrigin - The origin of the window message
*/
private isFromExtensionOrigin(messageOrigin: string): boolean {
return this.extensionOriginsSet.has(messageOrigin);
}
}

View File

@ -31,11 +31,12 @@ describe("AutofillOverlayPageElement", () => {
jest.spyOn(globalThis.document, "createElement");
});
it("initializes the button overlay page", () => {
const linkElement = autofillOverlayPageElement["initOverlayPage"](
it("initializes the button overlay page", async () => {
const linkElement = await autofillOverlayPageElement["initOverlayPage"](
"button",
"https://jest-testing-website.com",
translations,
"https://jest-testing-website.com/message-connector",
);
expect(globalThis.document.documentElement.setAttribute).toHaveBeenCalledWith(
@ -49,16 +50,16 @@ describe("AutofillOverlayPageElement", () => {
});
});
describe("postMessageToParent", () => {
describe("postMessageToConnector", () => {
it("skips posting a message to the parent if the message origin in not set", () => {
autofillOverlayPageElement["postMessageToParent"]({ command: "test" });
autofillOverlayPageElement["postMessageToConnector"]({ command: "test" });
expect(globalThis.parent.postMessage).not.toHaveBeenCalled();
});
it("posts a message to the parent", () => {
autofillOverlayPageElement["messageOrigin"] = "https://jest-testing-website.com";
autofillOverlayPageElement["postMessageToParent"]({ command: "test" });
autofillOverlayPageElement["postMessageToConnector"]({ command: "test" });
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "test" },

View File

@ -1,6 +1,6 @@
import { EVENTS } from "@bitwarden/common/autofill/constants";
import { RedirectFocusDirection } from "../../../utils/autofill-overlay.enum";
import { AutofillOverlayPort, RedirectFocusDirection } from "../../../utils/autofill-overlay.enum";
import {
AutofillOverlayPageElementWindowMessage,
WindowMessageHandlers,
@ -10,6 +10,7 @@ class AutofillOverlayPageElement extends HTMLElement {
protected shadowDom: ShadowRoot;
protected messageOrigin: string;
protected translations: Record<string, string>;
protected messageConnectorIframe: HTMLIFrameElement;
protected windowMessageHandlers: WindowMessageHandlers;
constructor() {
@ -25,16 +26,41 @@ class AutofillOverlayPageElement extends HTMLElement {
* @param elementName - The name of the element, e.g. "button" or "list"
* @param styleSheetUrl - The URL of the stylesheet to apply to the page
* @param translations - The translations to apply to the page
* @param messageConnectorUrl - The URL of the message connector to use
*/
protected initOverlayPage(
protected async initOverlayPage(
elementName: "button" | "list",
styleSheetUrl: string,
translations: Record<string, string>,
): HTMLLinkElement {
messageConnectorUrl: string,
): Promise<HTMLLinkElement> {
this.translations = translations;
globalThis.document.documentElement.setAttribute("lang", this.getTranslation("locale"));
globalThis.document.head.title = this.getTranslation(`${elementName}PageTitle`);
this.messageConnectorIframe = globalThis.document.createElement("iframe");
this.messageConnectorIframe.src = messageConnectorUrl;
this.messageConnectorIframe.style.opacity = "0";
this.messageConnectorIframe.style.position = "absolute";
this.messageConnectorIframe.style.width = "0";
this.messageConnectorIframe.style.height = "0";
this.messageConnectorIframe.style.border = "none";
this.messageConnectorIframe.style.pointerEvents = "none";
globalThis.document.body.appendChild(this.messageConnectorIframe);
await new Promise<void>((resolve) => {
this.messageConnectorIframe.addEventListener(EVENTS.LOAD, () => {
this.postMessageToConnector({
command: `initAutofillOverlayPort`,
portName:
elementName === "list"
? AutofillOverlayPort.ListMessageConnector
: AutofillOverlayPort.ButtonMessageConnector,
});
resolve();
});
});
this.shadowDom.innerHTML = "";
const linkElement = globalThis.document.createElement("link");
linkElement.setAttribute("rel", "stylesheet");
@ -48,12 +74,12 @@ class AutofillOverlayPageElement extends HTMLElement {
*
* @param message - The message to post
*/
protected postMessageToParent(message: AutofillOverlayPageElementWindowMessage) {
protected postMessageToConnector(message: AutofillOverlayPageElementWindowMessage) {
if (!this.messageOrigin) {
return;
}
globalThis.parent.postMessage(message, this.messageOrigin);
this.messageConnectorIframe.contentWindow.postMessage(message, "*");
}
/**
@ -111,7 +137,7 @@ class AutofillOverlayPageElement extends HTMLElement {
* Handles the window blur event.
*/
private handleWindowBlurEvent = () => {
this.postMessageToParent({ command: "overlayPageBlurred" });
this.postMessageToConnector({ command: "overlayPageBlurred" });
};
/**
@ -148,7 +174,7 @@ class AutofillOverlayPageElement extends HTMLElement {
* @param direction - The direction to redirect the focus out
*/
private redirectOverlayFocusOutMessage(direction: string) {
this.postMessageToParent({ command: "redirectOverlayFocusOut", direction });
this.postMessageToConnector({ command: "redirectOverlayFocusOut", direction });
}
}

View File

@ -173,6 +173,7 @@ function createInitAutofillOverlayButtonMessageMock(
translations: overlayPagesTranslations,
styleSheetUrl: "https://jest-testing-website.com",
authStatus: AuthenticationStatus.Unlocked,
messageConnectorUrl: "https://jest-testing-website.com/message-connector",
...customFields,
};
}
@ -203,6 +204,7 @@ function createInitAutofillOverlayListMessageMock(
styleSheetUrl: "https://jest-testing-website.com",
theme: ThemeType.Light,
authStatus: AuthenticationStatus.Unlocked,
messageConnectorUrl: "https://jest-testing-website.com/message-connector",
ciphers: [
createAutofillOverlayCipherDataMock(1, {
icon: {

View File

@ -5,7 +5,9 @@ const AutofillOverlayElement = {
const AutofillOverlayPort = {
Button: "autofill-overlay-button-port",
ButtonMessageConnector: "autofill-overlay-button-message-connector",
List: "autofill-overlay-list-port",
ListMessageConnector: "autofill-overlay-list-message-connector",
} as const;
const RedirectFocusDirection = {

View File

@ -115,6 +115,7 @@
"images/icon38_locked.png",
"overlay/button.html",
"overlay/list.html",
"overlay/message-connector.html",
"popup/fonts/*"
],
"applications": {

View File

@ -119,6 +119,7 @@
"images/icon38_locked.png",
"overlay/button.html",
"overlay/list.html",
"overlay/message-connector.html",
"popup/fonts/*"
],
"matches": ["<all_urls>"]

View File

@ -116,6 +116,11 @@ const plugins = [
filename: "overlay/list.html",
chunks: ["overlay/list"],
}),
new HtmlWebpackPlugin({
template: "./src/autofill/overlay/pages/message-connector/message-connector.html",
filename: "overlay/message-connector.html",
chunks: ["overlay/message-connector"],
}),
new CopyWebpackPlugin({
patterns: [
manifestVersion == 3
@ -173,6 +178,8 @@ const mainConfig = {
"notification/bar": "./src/autofill/notification/bar.ts",
"overlay/button": "./src/autofill/overlay/pages/button/bootstrap-autofill-overlay-button.ts",
"overlay/list": "./src/autofill/overlay/pages/list/bootstrap-autofill-overlay-list.ts",
"overlay/message-connector":
"./src/autofill/overlay/pages/message-connector/bootstrap-autofill-overlay-message-connector.ts",
"encrypt-worker": "../../libs/common/src/platform/services/cryptography/encrypt.worker.ts",
"content/lp-fileless-importer": "./src/tools/content/lp-fileless-importer.ts",
"content/send-on-installed-message": "./src/vault/content/send-on-installed-message.ts",