1
0
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:
Cesar Gonzalez 2024-03-21 16:25:07 -05:00
parent 6c2b93ec8d
commit 275e73e0cf
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
4 changed files with 100 additions and 4 deletions

View File

@ -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 = {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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.
*/