mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-09 00:11:30 +01:00
[PM-5189] Implementing a fallback to allow for getting subframe data through post messages if iframe cannot be correctly identified
This commit is contained in:
parent
6c2b93ec8d
commit
275e73e0cf
@ -12,9 +12,10 @@ type PageDetailsForTab = Record<
|
||||
>;
|
||||
|
||||
type SubFrameOffsetData = {
|
||||
url: string;
|
||||
url?: string;
|
||||
top: number;
|
||||
left: number;
|
||||
frameId?: number;
|
||||
} | null;
|
||||
|
||||
type SubFrameOffsetsForTab = Record<
|
||||
@ -110,6 +111,7 @@ type OverlayBackgroundExtensionMessageHandlers = {
|
||||
updateIsFieldCurrentlyFilling: ({ message }: BackgroundMessageParam) => void;
|
||||
checkIsInlineMenuButtonVisible: ({ sender }: BackgroundSenderParam) => void;
|
||||
checkIsInlineMenuListVisible: ({ sender }: BackgroundSenderParam) => void;
|
||||
updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
||||
};
|
||||
|
||||
type PortMessageParam = {
|
||||
|
@ -84,6 +84,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
(this.isCurrentlyFilling = message.isFieldCurrentlyFilling),
|
||||
checkIsInlineMenuButtonVisible: ({ sender }) => this.checkIsInlineMenuButtonVisible(sender),
|
||||
checkIsInlineMenuListVisible: ({ sender }) => this.checkIsInlineMenuListVisible(sender),
|
||||
updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender),
|
||||
};
|
||||
private readonly overlayButtonPortMessageHandlers: OverlayButtonPortMessageHandlers = {
|
||||
overlayButtonClicked: ({ port }) => this.handleOverlayButtonClicked(port),
|
||||
@ -127,6 +128,13 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
return value;
|
||||
}
|
||||
|
||||
updateSubFrameData(message: any, sender: chrome.runtime.MessageSender) {
|
||||
const subFrameOffsetsForTab = this.subFrameOffsetsForTab[sender.tab.id];
|
||||
if (subFrameOffsetsForTab) {
|
||||
subFrameOffsetsForTab.set(message.subFrameData.frameId, message.subFrameData);
|
||||
}
|
||||
}
|
||||
|
||||
private async checkIsInlineMenuListVisible(sender: chrome.runtime.MessageSender) {
|
||||
return await BrowserApi.tabSendMessage(
|
||||
sender.tab,
|
||||
@ -277,12 +285,26 @@ class OverlayBackground implements OverlayBackgroundInterface {
|
||||
while (frameDetails.parentFrameId !== -1) {
|
||||
const subFrameOffset: SubFrameOffsetData = await BrowserApi.tabSendMessage(
|
||||
tab,
|
||||
{ command: "getSubFrameOffsets", subFrameUrl: frameDetails.url },
|
||||
{
|
||||
command: "getSubFrameOffsets",
|
||||
subFrameUrl: frameDetails.url,
|
||||
subFrameId: frameDetails.documentId,
|
||||
},
|
||||
{ frameId: frameDetails.parentFrameId },
|
||||
);
|
||||
|
||||
if (!subFrameOffset) {
|
||||
subFrameOffsetsForTab.set(frameId, null);
|
||||
void BrowserApi.tabSendMessage(
|
||||
tab,
|
||||
{
|
||||
command: "getSubFrameOffsetsThroughWindowMessaging",
|
||||
subFrameId: frameId,
|
||||
},
|
||||
{
|
||||
frameId: frameId,
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ export type AutofillExtensionMessage = {
|
||||
fillScript?: AutofillScript;
|
||||
url?: string;
|
||||
subFrameUrl?: string;
|
||||
subFrameId?: string;
|
||||
pageDetailsUrl?: string;
|
||||
ciphers?: any;
|
||||
isInlineMenuHidden?: boolean;
|
||||
@ -40,6 +41,7 @@ export type AutofillExtensionMessageHandlers = {
|
||||
bgVaultItemRepromptPopoutOpened: () => void;
|
||||
updateAutofillOverlayVisibility: ({ message }: AutofillExtensionMessageParam) => void;
|
||||
getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise<SubFrameOffsetData>;
|
||||
getSubFrameOffsetsThroughWindowMessaging: ({ message }: AutofillExtensionMessageParam) => void;
|
||||
};
|
||||
|
||||
export interface AutofillInit {
|
||||
|
@ -33,6 +33,8 @@ class AutofillInit implements AutofillInitInterface {
|
||||
bgVaultItemRepromptPopoutOpened: () => this.blurAndRemoveOverlay(),
|
||||
updateAutofillOverlayVisibility: ({ message }) => this.updateAutofillOverlayVisibility(message),
|
||||
getSubFrameOffsets: ({ message }) => this.getSubFrameOffsets(message),
|
||||
getSubFrameOffsetsThroughWindowMessaging: ({ message }) =>
|
||||
this.getSubFrameOffsetsThroughWindowMessaging(message),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -71,6 +73,45 @@ class AutofillInit implements AutofillInitInterface {
|
||||
this.domElementVisibilityService,
|
||||
this.collectAutofillContentService,
|
||||
);
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
// if (event.source !== window) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (event.data.command === "calculateSubFramePositioning") {
|
||||
const subFrameData = event.data.subFrameData;
|
||||
let subFrameOffsets: SubFrameOffsetData;
|
||||
const iframes = document.querySelectorAll("iframe");
|
||||
for (let i = 0; i < iframes.length; i++) {
|
||||
if (iframes[i].contentWindow === event.source) {
|
||||
const iframeElement = iframes[i];
|
||||
subFrameOffsets = this.calculateSubFrameOffsets(
|
||||
iframeElement,
|
||||
subFrameData.url,
|
||||
subFrameData.frameId,
|
||||
);
|
||||
|
||||
subFrameData.top += subFrameOffsets.top;
|
||||
subFrameData.left += subFrameOffsets.left;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (globalThis.window.self !== globalThis.window.top) {
|
||||
globalThis.parent.postMessage(
|
||||
{ command: "calculateSubFramePositioning", subFrameData },
|
||||
"*",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
void sendExtensionMessage("updateSubFrameData", {
|
||||
subFrameData,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -245,14 +286,27 @@ class AutofillInit implements AutofillInitInterface {
|
||||
): Promise<SubFrameOffsetData | null> {
|
||||
const { subFrameUrl } = message;
|
||||
const subFrameUrlWithoutTrailingSlash = subFrameUrl?.replace(/\/$/, "");
|
||||
const iframeElement = document.querySelector(
|
||||
|
||||
let iframeElement: HTMLIFrameElement | null = null;
|
||||
const iframeElements = document.querySelectorAll(
|
||||
`iframe[src="${subFrameUrl}"], iframe[src="${subFrameUrlWithoutTrailingSlash}"]`,
|
||||
);
|
||||
) as NodeListOf<HTMLIFrameElement>;
|
||||
if (iframeElements.length === 1) {
|
||||
iframeElement = iframeElements[0];
|
||||
}
|
||||
|
||||
if (!iframeElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.calculateSubFrameOffsets(iframeElement, subFrameUrl);
|
||||
}
|
||||
|
||||
private calculateSubFrameOffsets(
|
||||
iframeElement: HTMLIFrameElement,
|
||||
subFrameUrl?: string,
|
||||
frameId?: number,
|
||||
): SubFrameOffsetData {
|
||||
const iframeRect = iframeElement.getBoundingClientRect();
|
||||
const iframeStyles = globalThis.getComputedStyle(iframeElement);
|
||||
const paddingLeft = parseInt(iframeStyles.getPropertyValue("padding-left"));
|
||||
@ -262,11 +316,27 @@ class AutofillInit implements AutofillInitInterface {
|
||||
|
||||
return {
|
||||
url: subFrameUrl,
|
||||
frameId,
|
||||
top: iframeRect.top + paddingTop + borderWidthTop,
|
||||
left: iframeRect.left + paddingLeft + borderWidthLeft,
|
||||
};
|
||||
}
|
||||
|
||||
private getSubFrameOffsetsThroughWindowMessaging(message: any) {
|
||||
globalThis.parent.postMessage(
|
||||
{
|
||||
command: "calculateSubFramePositioning",
|
||||
subFrameData: {
|
||||
url: window.location.href,
|
||||
frameId: message.subFrameId,
|
||||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the extension message listeners for the content script.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user