1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 09:43:23 +00:00

[PM-5189] Implementing methodology for gathering iframe rects within background script

This commit is contained in:
Cesar Gonzalez
2024-03-19 17:57:54 -05:00
parent bd68fff840
commit a3b12581f7
5 changed files with 80 additions and 18 deletions

View File

@@ -15,7 +15,7 @@ type SubFrameOffsetData = {
url: string; url: string;
top: number; top: number;
left: number; left: number;
}; } | null;
type SubFrameOffsetsForTab = Record< type SubFrameOffsetsForTab = Record<
chrome.runtime.MessageSender["tab"]["id"], chrome.runtime.MessageSender["tab"]["id"],

View File

@@ -42,6 +42,7 @@ import {
WebsiteIconData, WebsiteIconData,
PageDetailsForTab, PageDetailsForTab,
SubFrameOffsetsForTab, SubFrameOffsetsForTab,
SubFrameOffsetData,
} from "./abstractions/overlay.background"; } from "./abstractions/overlay.background";
class OverlayBackground implements OverlayBackgroundInterface { class OverlayBackground implements OverlayBackgroundInterface {
@@ -112,12 +113,15 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param tabId - Used to reference the page details of a specific tab * @param tabId - Used to reference the page details of a specific tab
*/ */
removePageDetails(tabId: number) { removePageDetails(tabId: number) {
if (!this.pageDetailsForTab[tabId]) { if (this.pageDetailsForTab[tabId]) {
return; this.pageDetailsForTab[tabId].clear();
delete this.pageDetailsForTab[tabId];
} }
this.pageDetailsForTab[tabId].clear(); if (this.subFrameOffsetsForTab[tabId]) {
delete this.pageDetailsForTab[tabId]; this.subFrameOffsetsForTab[tabId].clear();
delete this.subFrameOffsetsForTab[tabId];
}
} }
/** /**
@@ -212,7 +216,6 @@ class OverlayBackground implements OverlayBackgroundInterface {
}; };
if (pageDetails.frameId !== 0 && pageDetails.details.fields.length) { if (pageDetails.frameId !== 0 && pageDetails.details.fields.length) {
// NOT SURE I WANT THIS
void this.buildSubFrameOffset(pageDetails); void this.buildSubFrameOffset(pageDetails);
} }
@@ -226,13 +229,42 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
private async buildSubFrameOffset({ tab, frameId, details }: PageDetail) { private async buildSubFrameOffset({ tab, frameId, details }: PageDetail) {
const frameDetails = await BrowserApi.getFrameDetails({ const tabId = tab.id;
tabId: tab.id, let subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId];
frameId, if (!subFrameOffsetsForTab) {
}); this.subFrameOffsetsForTab[tabId] = new Map();
subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId];
}
// eslint-disable-next-line if (subFrameOffsetsForTab.get(frameId)) {
console.log(frameDetails); return;
}
const subFrameData = { url: details.url, top: 0, left: 0 };
let frameDetails = await BrowserApi.getFrameDetails({ tabId, frameId });
while (frameDetails.parentFrameId !== -1) {
const subFrameOffset: SubFrameOffsetData = await BrowserApi.tabSendMessage(
tab,
{ command: "getSubFrameOffsets", subFrameUrl: frameDetails.url },
{ frameId: frameDetails.parentFrameId },
);
if (!subFrameOffset) {
subFrameOffsetsForTab.set(frameId, null);
return;
}
subFrameData.top += subFrameOffset.top;
subFrameData.left += subFrameOffset.left;
frameDetails = await BrowserApi.getFrameDetails({
tabId,
frameId: frameDetails.parentFrameId,
});
}
subFrameOffsetsForTab.set(frameId, subFrameData);
} }
/** /**

View File

@@ -1,5 +1,6 @@
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { SubFrameOffsetData } from "../../background/abstractions/overlay.background";
import AutofillScript from "../../models/autofill-script"; import AutofillScript from "../../models/autofill-script";
type AutofillExtensionMessage = { type AutofillExtensionMessage = {
@@ -8,6 +9,7 @@ type AutofillExtensionMessage = {
sender?: string; sender?: string;
fillScript?: AutofillScript; fillScript?: AutofillScript;
url?: string; url?: string;
subFrameUrl?: string;
pageDetailsUrl?: string; pageDetailsUrl?: string;
ciphers?: any; ciphers?: any;
data?: { data?: {
@@ -36,6 +38,7 @@ type AutofillExtensionMessageHandlers = {
bgUnlockPopoutOpened: () => void; bgUnlockPopoutOpened: () => void;
bgVaultItemRepromptPopoutOpened: () => void; bgVaultItemRepromptPopoutOpened: () => void;
updateAutofillOverlayVisibility: ({ message }: AutofillExtensionMessageParam) => void; updateAutofillOverlayVisibility: ({ message }: AutofillExtensionMessageParam) => void;
getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise<SubFrameOffsetData>;
}; };
interface AutofillInit { interface AutofillInit {

View File

@@ -1,3 +1,4 @@
import { SubFrameOffsetData } from "../background/abstractions/overlay.background";
import AutofillPageDetails from "../models/autofill-page-details"; import AutofillPageDetails from "../models/autofill-page-details";
import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service"; import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service";
import CollectAutofillContentService from "../services/collect-autofill-content.service"; import CollectAutofillContentService from "../services/collect-autofill-content.service";
@@ -28,7 +29,7 @@ class AutofillInit implements AutofillInitInterface {
bgUnlockPopoutOpened: () => this.blurAndRemoveOverlay(), bgUnlockPopoutOpened: () => this.blurAndRemoveOverlay(),
bgVaultItemRepromptPopoutOpened: () => this.blurAndRemoveOverlay(), bgVaultItemRepromptPopoutOpened: () => this.blurAndRemoveOverlay(),
updateAutofillOverlayVisibility: ({ message }) => this.updateAutofillOverlayVisibility(message), updateAutofillOverlayVisibility: ({ message }) => this.updateAutofillOverlayVisibility(message),
getSubFrameOffsets: () => this.getSubFrameOffsets(), getSubFrameOffsets: ({ message }) => this.getSubFrameOffsets(message),
}; };
/** /**
@@ -250,7 +251,33 @@ class AutofillInit implements AutofillInitInterface {
this.autofillOverlayContentService.autofillOverlayVisibility = data?.autofillOverlayVisibility; this.autofillOverlayContentService.autofillOverlayVisibility = data?.autofillOverlayVisibility;
} }
private getSubFrameOffsets() {} private async getSubFrameOffsets(
message: AutofillExtensionMessage,
): Promise<SubFrameOffsetData | null> {
const { subFrameUrl } = message;
const subFrameUrlWithoutTrailingSlash = subFrameUrl?.replace(/\/$/, "");
// query iframe based on src attribute
const iframeElement = document.querySelector(
`iframe[src^="${subFrameUrlWithoutTrailingSlash}"]`,
);
if (!iframeElement) {
return null;
}
const iframeRect = iframeElement.getBoundingClientRect();
const iframeStyles = globalThis.getComputedStyle(iframeElement);
const paddingLeft = parseInt(iframeStyles.getPropertyValue("padding-left"));
const paddingTop = parseInt(iframeStyles.getPropertyValue("padding-top"));
const borderWidthLeft = parseInt(iframeStyles.getPropertyValue("border-left-width"));
const borderWidthTop = parseInt(iframeStyles.getPropertyValue("border-top-width"));
return {
url: subFrameUrl,
top: iframeRect.top + paddingTop + borderWidthTop,
left: iframeRect.left + paddingLeft + borderWidthLeft,
};
}
/** /**
* Sets up the extension message listeners for the content script. * Sets up the extension message listeners for the content script.

View File

@@ -178,17 +178,17 @@ export class BrowserApi {
tab: chrome.tabs.Tab, tab: chrome.tabs.Tab,
obj: T, obj: T,
options: chrome.tabs.MessageSendOptions = null, options: chrome.tabs.MessageSendOptions = null,
): Promise<void> { ): Promise<any> {
if (!tab || !tab.id) { if (!tab || !tab.id) {
return; return;
} }
return new Promise<void>((resolve) => { return new Promise<any>((resolve) => {
chrome.tabs.sendMessage(tab.id, obj, options, () => { chrome.tabs.sendMessage(tab.id, obj, options, (response) => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
// Some error happened // Some error happened
} }
resolve(); resolve(response);
}); });
}); });
} }