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:
parent
3313807acb
commit
d6d52e5e5e
@ -12,10 +12,10 @@ type PageDetailsForTab = Record<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
type SubFrameOffsetData = {
|
type SubFrameOffsetData = {
|
||||||
|
frameId?: number;
|
||||||
url?: string;
|
url?: string;
|
||||||
top: number;
|
top: number;
|
||||||
left: number;
|
left: number;
|
||||||
frameId?: number;
|
|
||||||
} | null;
|
} | null;
|
||||||
|
|
||||||
type SubFrameOffsetsForTab = Record<
|
type SubFrameOffsetsForTab = Record<
|
||||||
@ -49,9 +49,9 @@ type OverlayBackgroundExtensionMessage = {
|
|||||||
forceCloseOverlay?: boolean;
|
forceCloseOverlay?: boolean;
|
||||||
isOverlayHidden?: boolean;
|
isOverlayHidden?: boolean;
|
||||||
setTransparentOverlay?: boolean;
|
setTransparentOverlay?: boolean;
|
||||||
data?: LockedVaultPendingNotificationsData;
|
|
||||||
isFieldCurrentlyFocused?: boolean;
|
isFieldCurrentlyFocused?: boolean;
|
||||||
isCurrentlyFilling?: boolean;
|
isCurrentlyFilling?: boolean;
|
||||||
|
data?: LockedVaultPendingNotificationsData;
|
||||||
} & OverlayAddNewItemMessage;
|
} & OverlayAddNewItemMessage;
|
||||||
|
|
||||||
type OverlayPortMessage = {
|
type OverlayPortMessage = {
|
||||||
@ -132,6 +132,7 @@ type OverlayButtonPortMessageHandlers = {
|
|||||||
forceCloseAutofillOverlay: ({ port }: PortConnectionParam) => void;
|
forceCloseAutofillOverlay: ({ port }: PortConnectionParam) => void;
|
||||||
overlayPageBlurred: () => void;
|
overlayPageBlurred: () => void;
|
||||||
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
|
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
|
||||||
|
getPageColorScheme: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OverlayListPortMessageHandlers = {
|
type OverlayListPortMessageHandlers = {
|
||||||
@ -144,6 +145,7 @@ type OverlayListPortMessageHandlers = {
|
|||||||
addNewVaultItem: ({ port }: PortConnectionParam) => void;
|
addNewVaultItem: ({ port }: PortConnectionParam) => void;
|
||||||
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
|
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
|
||||||
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
|
redirectOverlayFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
|
||||||
|
updateAutofillOverlayListHeight: ({ message, port }: PortOnMessageHandlerParams) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OverlayBackground {
|
interface OverlayBackground {
|
||||||
|
@ -95,6 +95,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
this.closeOverlay(port.sender, { forceCloseOverlay: true }),
|
this.closeOverlay(port.sender, { forceCloseOverlay: true }),
|
||||||
overlayPageBlurred: () => this.checkOverlayListFocused(),
|
overlayPageBlurred: () => this.checkOverlayListFocused(),
|
||||||
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
|
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
|
||||||
|
getPageColorScheme: () => {
|
||||||
|
this.overlayButtonPort?.postMessage({
|
||||||
|
command: "getPageColorScheme",
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
private readonly overlayListPortMessageHandlers: OverlayListPortMessageHandlers = {
|
private readonly overlayListPortMessageHandlers: OverlayListPortMessageHandlers = {
|
||||||
checkAutofillOverlayButtonFocused: () => this.checkOverlayButtonFocused(),
|
checkAutofillOverlayButtonFocused: () => this.checkOverlayButtonFocused(),
|
||||||
@ -106,6 +111,12 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port),
|
addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port),
|
||||||
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
|
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
|
||||||
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
|
redirectOverlayFocusOut: ({ message, port }) => this.redirectOverlayFocusOut(message, port),
|
||||||
|
updateAutofillOverlayListHeight: ({ message }) => {
|
||||||
|
this.overlayListPort?.postMessage({
|
||||||
|
command: "updateIframePosition",
|
||||||
|
styles: message.styles,
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -832,7 +843,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
await BrowserApi.sendMessage("inlineAutofillMenuRefreshAddEditCipher");
|
await BrowserApi.sendMessage("inlineAutofillMenuRefreshAddEditCipher");
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateIsFieldCurrentlyFocused({ message }: OverlayBackgroundExtensionMessage) {
|
private updateIsFieldCurrentlyFocused(message: OverlayBackgroundExtensionMessage) {
|
||||||
this.isFieldCurrentlyFocused = message.isFieldCurrentlyFocused;
|
this.isFieldCurrentlyFocused = message.isFieldCurrentlyFocused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -910,6 +921,14 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param port - The port that connected to the extension background
|
* @param port - The port that connected to the extension background
|
||||||
*/
|
*/
|
||||||
private handlePortOnConnect = async (port: chrome.runtime.Port) => {
|
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 isOverlayListPort = port.name === AutofillOverlayPort.List;
|
||||||
const isOverlayButtonPort = port.name === AutofillOverlayPort.Button;
|
const isOverlayButtonPort = port.name === AutofillOverlayPort.Button;
|
||||||
|
|
||||||
@ -923,7 +942,6 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
this.overlayButtonPort = port;
|
this.overlayButtonPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
port.onMessage.addListener(this.handleOverlayElementPortMessage);
|
|
||||||
port.onDisconnect.addListener(this.handlePortOnDisconnect);
|
port.onDisconnect.addListener(this.handlePortOnDisconnect);
|
||||||
port.postMessage({
|
port.postMessage({
|
||||||
command: `initAutofillOverlay${isOverlayListPort ? "List" : "Button"}`,
|
command: `initAutofillOverlay${isOverlayListPort ? "List" : "Button"}`,
|
||||||
@ -932,6 +950,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
||||||
translations: this.getTranslations(),
|
translations: this.getTranslations(),
|
||||||
ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null,
|
ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null,
|
||||||
|
messageConnectorUrl: chrome.runtime.getURL("overlay/message-connector.html"),
|
||||||
});
|
});
|
||||||
void this.updateOverlayPosition(
|
void this.updateOverlayPosition(
|
||||||
{
|
{
|
||||||
@ -956,11 +975,11 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
const command = message?.command;
|
const command = message?.command;
|
||||||
let handler: CallableFunction | undefined;
|
let handler: CallableFunction | undefined;
|
||||||
|
|
||||||
if (port.name === AutofillOverlayPort.Button) {
|
if (port.name === AutofillOverlayPort.ButtonMessageConnector) {
|
||||||
handler = this.overlayButtonPortMessageHandlers[command];
|
handler = this.overlayButtonPortMessageHandlers[command];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port.name === AutofillOverlayPort.List) {
|
if (port.name === AutofillOverlayPort.ListMessageConnector) {
|
||||||
handler = this.overlayListPortMessageHandlers[command];
|
handler = this.overlayListPortMessageHandlers[command];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ const notificationBarWindowMessageHandlers: NotificationBarWindowMessageHandlers
|
|||||||
globalThis.addEventListener("load", load);
|
globalThis.addEventListener("load", load);
|
||||||
function load() {
|
function load() {
|
||||||
setupWindowMessageListener();
|
setupWindowMessageListener();
|
||||||
postMessageToParent({ command: "initNotificationBar" });
|
postMessageToConnector({ command: "initNotificationBar" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function initNotificationBar(message: NotificationBarWindowMessage) {
|
function initNotificationBar(message: NotificationBarWindowMessage) {
|
||||||
@ -392,6 +392,6 @@ function setNotificationBarTheme() {
|
|||||||
document.documentElement.classList.add(`theme_${theme}`);
|
document.documentElement.classList.add(`theme_${theme}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function postMessageToParent(message: NotificationBarWindowMessage) {
|
function postMessageToConnector(message: NotificationBarWindowMessage) {
|
||||||
globalThis.parent.postMessage(message, windowMessageOrigin || "*");
|
globalThis.parent.postMessage(message, windowMessageOrigin || "*");
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ type UpdateAuthStatusMessage = OverlayButtonMessage & { authStatus: Authenticati
|
|||||||
type InitAutofillOverlayButtonMessage = UpdateAuthStatusMessage & {
|
type InitAutofillOverlayButtonMessage = UpdateAuthStatusMessage & {
|
||||||
styleSheetUrl: string;
|
styleSheetUrl: string;
|
||||||
translations: Record<string, string>;
|
translations: Record<string, string>;
|
||||||
|
messageConnectorUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OverlayButtonWindowMessageHandlers = {
|
type OverlayButtonWindowMessageHandlers = {
|
||||||
|
@ -7,7 +7,6 @@ type AutofillOverlayIframeExtensionMessage = {
|
|||||||
type AutofillOverlayIframeWindowMessageHandlers = {
|
type AutofillOverlayIframeWindowMessageHandlers = {
|
||||||
[key: string]: CallableFunction;
|
[key: string]: CallableFunction;
|
||||||
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
updateAutofillOverlayListHeight: (message: AutofillOverlayIframeExtensionMessage) => void;
|
||||||
getPageColorScheme: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type AutofillOverlayIframeExtensionMessageParam = {
|
type AutofillOverlayIframeExtensionMessageParam = {
|
||||||
@ -19,6 +18,7 @@ type BackgroundPortMessageHandlers = {
|
|||||||
initAutofillOverlayList: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
initAutofillOverlayList: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||||
updateIframePosition: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
updateIframePosition: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||||
updateOverlayHidden: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
updateOverlayHidden: ({ message }: AutofillOverlayIframeExtensionMessageParam) => void;
|
||||||
|
getPageColorScheme: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface AutofillOverlayIframeService {
|
interface AutofillOverlayIframeService {
|
||||||
|
@ -14,6 +14,7 @@ type InitAutofillOverlayListMessage = OverlayListMessage & {
|
|||||||
theme: string;
|
theme: string;
|
||||||
translations: Record<string, string>;
|
translations: Record<string, string>;
|
||||||
ciphers?: OverlayCipherData[];
|
ciphers?: OverlayCipherData[];
|
||||||
|
messageConnectorUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type OverlayListWindowMessageHandlers = {
|
type OverlayListWindowMessageHandlers = {
|
||||||
|
@ -70,13 +70,13 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
|
|||||||
* unobserve the body element to ensure the mutation observer no
|
* unobserve the body element to ensure the mutation observer no
|
||||||
* longer triggers.
|
* longer triggers.
|
||||||
*/
|
*/
|
||||||
private removeInlineMenu = (message: any) => {
|
private removeInlineMenu = (message?: AutofillExtensionMessage) => {
|
||||||
if (message.overlayElement === AutofillOverlayElement.Button) {
|
if (message?.overlayElement === AutofillOverlayElement.Button) {
|
||||||
this.removeInlineMenuButton();
|
this.removeInlineMenuButton();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.overlayElement === AutofillOverlayElement.List) {
|
if (message?.overlayElement === AutofillOverlayElement.List) {
|
||||||
this.removeInlineMenuList();
|
this.removeInlineMenuList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -408,7 +408,7 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
|
|||||||
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
||||||
this.mutationObserverIterations = 0;
|
this.mutationObserverIterations = 0;
|
||||||
void this.sendExtensionMessage("blurMostRecentOverlayField");
|
void this.sendExtensionMessage("blurMostRecentOverlayField");
|
||||||
this.removeInlineMenu({ forceClose: true });
|
this.removeInlineMenu();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -417,6 +417,6 @@ export class InlineMenuElements implements InlineMenuElementsInterface {
|
|||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
this.documentElementMutationObserver?.disconnect();
|
this.documentElementMutationObserver?.disconnect();
|
||||||
this.removeInlineMenu({ forceClose: true });
|
this.removeInlineMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
|
|
||||||
import { setElementStyles } from "../../utils";
|
import { sendExtensionMessage, setElementStyles } from "../../utils";
|
||||||
import {
|
import {
|
||||||
BackgroundPortMessageHandlers,
|
BackgroundPortMessageHandlers,
|
||||||
AutofillOverlayIframeService as AutofillOverlayIframeServiceInterface,
|
AutofillOverlayIframeService as AutofillOverlayIframeServiceInterface,
|
||||||
AutofillOverlayIframeExtensionMessage,
|
AutofillOverlayIframeExtensionMessage,
|
||||||
AutofillOverlayIframeWindowMessageHandlers,
|
|
||||||
} from "../abstractions/autofill-overlay-iframe.service";
|
} from "../abstractions/autofill-overlay-iframe.service";
|
||||||
|
|
||||||
class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterface {
|
class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterface {
|
||||||
private port: chrome.runtime.Port | null = null;
|
private port: chrome.runtime.Port | null = null;
|
||||||
private extensionOriginsSet: Set<string>;
|
|
||||||
private iframeMutationObserver: MutationObserver;
|
private iframeMutationObserver: MutationObserver;
|
||||||
private iframe: HTMLIFrameElement;
|
private iframe: HTMLIFrameElement;
|
||||||
private ariaAlertElement: HTMLDivElement;
|
private ariaAlertElement: HTMLDivElement;
|
||||||
@ -42,15 +40,11 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
private foreignMutationsCount = 0;
|
private foreignMutationsCount = 0;
|
||||||
private mutationObserverIterations = 0;
|
private mutationObserverIterations = 0;
|
||||||
private mutationObserverIterationsResetTimeout: number | NodeJS.Timeout;
|
private mutationObserverIterationsResetTimeout: number | NodeJS.Timeout;
|
||||||
private readonly windowMessageHandlers: AutofillOverlayIframeWindowMessageHandlers = {
|
|
||||||
updateAutofillOverlayListHeight: (message) =>
|
|
||||||
this.updateElementStyles(this.iframe, message.styles),
|
|
||||||
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
|
|
||||||
};
|
|
||||||
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
|
private readonly backgroundPortMessageHandlers: BackgroundPortMessageHandlers = {
|
||||||
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
|
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
|
||||||
updateIframePosition: ({ message }) => this.updateIframePosition(message.styles),
|
updateIframePosition: ({ message }) => this.updateIframePosition(message.styles),
|
||||||
updateOverlayHidden: ({ message }) => this.updateElementStyles(this.iframe, message.styles),
|
updateOverlayHidden: ({ message }) => this.updateElementStyles(this.iframe, message.styles),
|
||||||
|
getPageColorScheme: () => this.updateOverlayPageColorScheme(),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -58,11 +52,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
private portName: string,
|
private portName: string,
|
||||||
private shadow: ShadowRoot,
|
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);
|
this.iframeMutationObserver = new MutationObserver(this.handleMutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +123,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
this.port = chrome.runtime.connect({ name: this.portName });
|
this.port = chrome.runtime.connect({ name: this.portName });
|
||||||
this.port.onDisconnect.addListener(this.handlePortDisconnect);
|
this.port.onDisconnect.addListener(this.handlePortDisconnect);
|
||||||
this.port.onMessage.addListener(this.handlePortMessage);
|
this.port.onMessage.addListener(this.handlePortMessage);
|
||||||
globalThis.addEventListener(EVENTS.MESSAGE, this.handleWindowMessage);
|
|
||||||
|
|
||||||
this.announceAriaAlert();
|
this.announceAriaAlert();
|
||||||
};
|
};
|
||||||
@ -168,7 +156,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updateElementStyles(this.iframe, { opacity: "0", height: "0px", display: "block" });
|
this.updateElementStyles(this.iframe, { opacity: "0", height: "0px", display: "block" });
|
||||||
globalThis.removeEventListener("message", this.handleWindowMessage);
|
|
||||||
this.unobserveIframe();
|
this.unobserveIframe();
|
||||||
this.port?.onMessage.removeListener(this.handlePortMessage);
|
this.port?.onMessage.removeListener(this.handlePortMessage);
|
||||||
this.port?.onDisconnect.removeListener(this.handlePortDisconnect);
|
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
|
* 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
|
* will also unobserve the element if it is the iframe element. This is
|
||||||
@ -311,17 +274,6 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
this.observeIframe();
|
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
|
* Handles mutations to the iframe element. The ensures that the iframe
|
||||||
* element's styles are not modified by a third party source.
|
* 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
|
* Handles mutations to the iframe element's attributes. This ensures that
|
||||||
* the iframe element's attributes are not modified by a third party source.
|
* 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) {
|
if (this.foreignMutationsCount >= 10) {
|
||||||
this.port?.postMessage({ command: "forceCloseAutofillOverlay" });
|
this.forceCloseAutofillOverlay();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +377,7 @@ class AutofillOverlayIframeService implements AutofillOverlayIframeServiceInterf
|
|||||||
if (this.mutationObserverIterations > 20) {
|
if (this.mutationObserverIterations > 20) {
|
||||||
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
clearTimeout(this.mutationObserverIterationsResetTimeout);
|
||||||
resetCounters();
|
resetCounters();
|
||||||
this.port?.postMessage({ command: "forceCloseAutofillOverlay" });
|
this.forceCloseAutofillOverlay();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,20 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
* @param authStatus - The authentication status of the user
|
* @param authStatus - The authentication status of the user
|
||||||
* @param styleSheetUrl - The URL of the stylesheet to apply to the page
|
* @param styleSheetUrl - The URL of the stylesheet to apply to the page
|
||||||
* @param translations - The translations 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({
|
private async initAutofillOverlayButton({
|
||||||
authStatus,
|
authStatus,
|
||||||
styleSheetUrl,
|
styleSheetUrl,
|
||||||
translations,
|
translations,
|
||||||
|
messageConnectorUrl,
|
||||||
}: InitAutofillOverlayButtonMessage) {
|
}: InitAutofillOverlayButtonMessage) {
|
||||||
const linkElement = this.initOverlayPage("button", styleSheetUrl, translations);
|
const linkElement = await this.initOverlayPage(
|
||||||
|
"button",
|
||||||
|
styleSheetUrl,
|
||||||
|
translations,
|
||||||
|
messageConnectorUrl,
|
||||||
|
);
|
||||||
this.buttonElement.tabIndex = -1;
|
this.buttonElement.tabIndex = -1;
|
||||||
this.buttonElement.type = "button";
|
this.buttonElement.type = "button";
|
||||||
this.buttonElement.classList.add("overlay-button");
|
this.buttonElement.classList.add("overlay-button");
|
||||||
@ -63,7 +68,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
this.getTranslation("toggleBitwardenVaultOverlay"),
|
this.getTranslation("toggleBitwardenVaultOverlay"),
|
||||||
);
|
);
|
||||||
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
|
this.buttonElement.addEventListener(EVENTS.CLICK, this.handleButtonElementClick);
|
||||||
this.postMessageToParent({ command: "getPageColorScheme" });
|
this.postMessageToConnector({ command: "getPageColorScheme" });
|
||||||
|
|
||||||
this.updateAuthStatus(authStatus);
|
this.updateAuthStatus(authStatus);
|
||||||
|
|
||||||
@ -103,7 +108,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
* parent window indicating that the button was clicked.
|
* parent window indicating that the button was clicked.
|
||||||
*/
|
*/
|
||||||
private handleButtonElementClick = () => {
|
private handleButtonElementClick = () => {
|
||||||
this.postMessageToParent({ command: "overlayButtonClicked" });
|
this.postMessageToConnector({ command: "overlayButtonClicked" });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +120,7 @@ class AutofillOverlayButton extends AutofillOverlayPageElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.postMessageToParent({ command: "closeAutofillOverlay" });
|
this.postMessageToConnector({ command: "closeAutofillOverlay" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
* @param theme - The theme to use for the overlay list.
|
* @param theme - The theme to use for the overlay list.
|
||||||
* @param authStatus - The current authentication status.
|
* @param authStatus - The current authentication status.
|
||||||
* @param ciphers - The ciphers to display in the overlay list.
|
* @param ciphers - The ciphers to display in the overlay list.
|
||||||
|
* @param messageConnectorUrl - The URL of the message connector to use.
|
||||||
*/
|
*/
|
||||||
private async initAutofillOverlayList({
|
private async initAutofillOverlayList({
|
||||||
translations,
|
translations,
|
||||||
@ -51,8 +52,14 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
theme,
|
theme,
|
||||||
authStatus,
|
authStatus,
|
||||||
ciphers,
|
ciphers,
|
||||||
|
messageConnectorUrl,
|
||||||
}: InitAutofillOverlayListMessage) {
|
}: InitAutofillOverlayListMessage) {
|
||||||
const linkElement = this.initOverlayPage("button", styleSheetUrl, translations);
|
const linkElement = await this.initOverlayPage(
|
||||||
|
"list",
|
||||||
|
styleSheetUrl,
|
||||||
|
translations,
|
||||||
|
messageConnectorUrl,
|
||||||
|
);
|
||||||
|
|
||||||
const themeClass = `theme_${theme}`;
|
const themeClass = `theme_${theme}`;
|
||||||
globalThis.document.documentElement.classList.add(themeClass);
|
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.
|
* Sends a message to the parent window to unlock the vault.
|
||||||
*/
|
*/
|
||||||
private handleUnlockButtonClick = () => {
|
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.
|
* Sends a message to the parent window to add a new vault item.
|
||||||
*/
|
*/
|
||||||
private handeNewItemButtonClick = () => {
|
private handeNewItemButtonClick = () => {
|
||||||
this.postMessageToParent({ command: "addNewVaultItem" });
|
this.postMessageToConnector({ command: "addNewVaultItem" });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,7 +283,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
private handleFillCipherClickEvent = (cipher: OverlayCipherData) => {
|
private handleFillCipherClickEvent = (cipher: OverlayCipherData) => {
|
||||||
return this.useEventHandlersMemo(
|
return this.useEventHandlersMemo(
|
||||||
() =>
|
() =>
|
||||||
this.postMessageToParent({
|
this.postMessageToConnector({
|
||||||
command: "fillSelectedListItem",
|
command: "fillSelectedListItem",
|
||||||
overlayCipherId: cipher.id,
|
overlayCipherId: cipher.id,
|
||||||
}),
|
}),
|
||||||
@ -341,7 +348,8 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
*/
|
*/
|
||||||
private handleViewCipherClickEvent = (cipher: OverlayCipherData) => {
|
private handleViewCipherClickEvent = (cipher: OverlayCipherData) => {
|
||||||
return this.useEventHandlersMemo(
|
return this.useEventHandlersMemo(
|
||||||
() => this.postMessageToParent({ command: "viewSelectedCipher", overlayCipherId: cipher.id }),
|
() =>
|
||||||
|
this.postMessageToConnector({ command: "viewSelectedCipher", overlayCipherId: cipher.id }),
|
||||||
`${cipher.id}-view-cipher-button-click-handler`,
|
`${cipher.id}-view-cipher-button-click-handler`,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -476,7 +484,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.postMessageToParent({ command: "checkAutofillOverlayButtonFocused" });
|
this.postMessageToConnector({ command: "checkAutofillOverlayButtonFocused" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -533,7 +541,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { height } = entry.contentRect;
|
const { height } = entry.contentRect;
|
||||||
this.postMessageToParent({
|
this.postMessageToConnector({
|
||||||
command: "updateAutofillOverlayListHeight",
|
command: "updateAutofillOverlayListHeight",
|
||||||
styles: { height: `${height}px` },
|
styles: { height: `${height}px` },
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
import { AutofillOverlayMessageConnector } from "./message-connector";
|
||||||
|
|
||||||
|
(() => new AutofillOverlayMessageConnector())();
|
@ -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>
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -31,11 +31,12 @@ describe("AutofillOverlayPageElement", () => {
|
|||||||
jest.spyOn(globalThis.document, "createElement");
|
jest.spyOn(globalThis.document, "createElement");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("initializes the button overlay page", () => {
|
it("initializes the button overlay page", async () => {
|
||||||
const linkElement = autofillOverlayPageElement["initOverlayPage"](
|
const linkElement = await autofillOverlayPageElement["initOverlayPage"](
|
||||||
"button",
|
"button",
|
||||||
"https://jest-testing-website.com",
|
"https://jest-testing-website.com",
|
||||||
translations,
|
translations,
|
||||||
|
"https://jest-testing-website.com/message-connector",
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(globalThis.document.documentElement.setAttribute).toHaveBeenCalledWith(
|
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", () => {
|
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();
|
expect(globalThis.parent.postMessage).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("posts a message to the parent", () => {
|
it("posts a message to the parent", () => {
|
||||||
autofillOverlayPageElement["messageOrigin"] = "https://jest-testing-website.com";
|
autofillOverlayPageElement["messageOrigin"] = "https://jest-testing-website.com";
|
||||||
autofillOverlayPageElement["postMessageToParent"]({ command: "test" });
|
autofillOverlayPageElement["postMessageToConnector"]({ command: "test" });
|
||||||
|
|
||||||
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
|
expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
|
||||||
{ command: "test" },
|
{ command: "test" },
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
import { EVENTS } from "@bitwarden/common/autofill/constants";
|
||||||
|
|
||||||
import { RedirectFocusDirection } from "../../../utils/autofill-overlay.enum";
|
import { AutofillOverlayPort, RedirectFocusDirection } from "../../../utils/autofill-overlay.enum";
|
||||||
import {
|
import {
|
||||||
AutofillOverlayPageElementWindowMessage,
|
AutofillOverlayPageElementWindowMessage,
|
||||||
WindowMessageHandlers,
|
WindowMessageHandlers,
|
||||||
@ -10,6 +10,7 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
protected shadowDom: ShadowRoot;
|
protected shadowDom: ShadowRoot;
|
||||||
protected messageOrigin: string;
|
protected messageOrigin: string;
|
||||||
protected translations: Record<string, string>;
|
protected translations: Record<string, string>;
|
||||||
|
protected messageConnectorIframe: HTMLIFrameElement;
|
||||||
protected windowMessageHandlers: WindowMessageHandlers;
|
protected windowMessageHandlers: WindowMessageHandlers;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -25,16 +26,41 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
* @param elementName - The name of the element, e.g. "button" or "list"
|
* @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 styleSheetUrl - The URL of the stylesheet to apply to the page
|
||||||
* @param translations - The translations 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",
|
elementName: "button" | "list",
|
||||||
styleSheetUrl: string,
|
styleSheetUrl: string,
|
||||||
translations: Record<string, string>,
|
translations: Record<string, string>,
|
||||||
): HTMLLinkElement {
|
messageConnectorUrl: string,
|
||||||
|
): Promise<HTMLLinkElement> {
|
||||||
this.translations = translations;
|
this.translations = translations;
|
||||||
globalThis.document.documentElement.setAttribute("lang", this.getTranslation("locale"));
|
globalThis.document.documentElement.setAttribute("lang", this.getTranslation("locale"));
|
||||||
globalThis.document.head.title = this.getTranslation(`${elementName}PageTitle`);
|
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 = "";
|
this.shadowDom.innerHTML = "";
|
||||||
const linkElement = globalThis.document.createElement("link");
|
const linkElement = globalThis.document.createElement("link");
|
||||||
linkElement.setAttribute("rel", "stylesheet");
|
linkElement.setAttribute("rel", "stylesheet");
|
||||||
@ -48,12 +74,12 @@ class AutofillOverlayPageElement extends HTMLElement {
|
|||||||
*
|
*
|
||||||
* @param message - The message to post
|
* @param message - The message to post
|
||||||
*/
|
*/
|
||||||
protected postMessageToParent(message: AutofillOverlayPageElementWindowMessage) {
|
protected postMessageToConnector(message: AutofillOverlayPageElementWindowMessage) {
|
||||||
if (!this.messageOrigin) {
|
if (!this.messageOrigin) {
|
||||||
return;
|
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.
|
* Handles the window blur event.
|
||||||
*/
|
*/
|
||||||
private handleWindowBlurEvent = () => {
|
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
|
* @param direction - The direction to redirect the focus out
|
||||||
*/
|
*/
|
||||||
private redirectOverlayFocusOutMessage(direction: string) {
|
private redirectOverlayFocusOutMessage(direction: string) {
|
||||||
this.postMessageToParent({ command: "redirectOverlayFocusOut", direction });
|
this.postMessageToConnector({ command: "redirectOverlayFocusOut", direction });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +173,7 @@ function createInitAutofillOverlayButtonMessageMock(
|
|||||||
translations: overlayPagesTranslations,
|
translations: overlayPagesTranslations,
|
||||||
styleSheetUrl: "https://jest-testing-website.com",
|
styleSheetUrl: "https://jest-testing-website.com",
|
||||||
authStatus: AuthenticationStatus.Unlocked,
|
authStatus: AuthenticationStatus.Unlocked,
|
||||||
|
messageConnectorUrl: "https://jest-testing-website.com/message-connector",
|
||||||
...customFields,
|
...customFields,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -203,6 +204,7 @@ function createInitAutofillOverlayListMessageMock(
|
|||||||
styleSheetUrl: "https://jest-testing-website.com",
|
styleSheetUrl: "https://jest-testing-website.com",
|
||||||
theme: ThemeType.Light,
|
theme: ThemeType.Light,
|
||||||
authStatus: AuthenticationStatus.Unlocked,
|
authStatus: AuthenticationStatus.Unlocked,
|
||||||
|
messageConnectorUrl: "https://jest-testing-website.com/message-connector",
|
||||||
ciphers: [
|
ciphers: [
|
||||||
createAutofillOverlayCipherDataMock(1, {
|
createAutofillOverlayCipherDataMock(1, {
|
||||||
icon: {
|
icon: {
|
||||||
|
@ -5,7 +5,9 @@ const AutofillOverlayElement = {
|
|||||||
|
|
||||||
const AutofillOverlayPort = {
|
const AutofillOverlayPort = {
|
||||||
Button: "autofill-overlay-button-port",
|
Button: "autofill-overlay-button-port",
|
||||||
|
ButtonMessageConnector: "autofill-overlay-button-message-connector",
|
||||||
List: "autofill-overlay-list-port",
|
List: "autofill-overlay-list-port",
|
||||||
|
ListMessageConnector: "autofill-overlay-list-message-connector",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const RedirectFocusDirection = {
|
const RedirectFocusDirection = {
|
||||||
|
@ -115,6 +115,7 @@
|
|||||||
"images/icon38_locked.png",
|
"images/icon38_locked.png",
|
||||||
"overlay/button.html",
|
"overlay/button.html",
|
||||||
"overlay/list.html",
|
"overlay/list.html",
|
||||||
|
"overlay/message-connector.html",
|
||||||
"popup/fonts/*"
|
"popup/fonts/*"
|
||||||
],
|
],
|
||||||
"applications": {
|
"applications": {
|
||||||
|
@ -119,6 +119,7 @@
|
|||||||
"images/icon38_locked.png",
|
"images/icon38_locked.png",
|
||||||
"overlay/button.html",
|
"overlay/button.html",
|
||||||
"overlay/list.html",
|
"overlay/list.html",
|
||||||
|
"overlay/message-connector.html",
|
||||||
"popup/fonts/*"
|
"popup/fonts/*"
|
||||||
],
|
],
|
||||||
"matches": ["<all_urls>"]
|
"matches": ["<all_urls>"]
|
||||||
|
@ -116,6 +116,11 @@ const plugins = [
|
|||||||
filename: "overlay/list.html",
|
filename: "overlay/list.html",
|
||||||
chunks: ["overlay/list"],
|
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({
|
new CopyWebpackPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
manifestVersion == 3
|
manifestVersion == 3
|
||||||
@ -173,6 +178,8 @@ const mainConfig = {
|
|||||||
"notification/bar": "./src/autofill/notification/bar.ts",
|
"notification/bar": "./src/autofill/notification/bar.ts",
|
||||||
"overlay/button": "./src/autofill/overlay/pages/button/bootstrap-autofill-overlay-button.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/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",
|
"encrypt-worker": "../../libs/common/src/platform/services/cryptography/encrypt.worker.ts",
|
||||||
"content/lp-fileless-importer": "./src/tools/content/lp-fileless-importer.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",
|
"content/send-on-installed-message": "./src/vault/content/send-on-installed-message.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user