From a3b12581f743a8762bb7fa4dc0e2d8e616f0e756 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Tue, 19 Mar 2024 17:57:54 -0500 Subject: [PATCH] [PM-5189] Implementing methodology for gathering iframe rects within background script --- .../abstractions/overlay.background.ts | 2 +- .../autofill/background/overlay.background.ts | 54 +++++++++++++++---- .../content/abstractions/autofill-init.ts | 3 ++ .../src/autofill/content/autofill-init.ts | 31 ++++++++++- .../src/platform/browser/browser-api.ts | 8 +-- 5 files changed, 80 insertions(+), 18 deletions(-) diff --git a/apps/browser/src/autofill/background/abstractions/overlay.background.ts b/apps/browser/src/autofill/background/abstractions/overlay.background.ts index 735ce113ffa..6be63577369 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay.background.ts @@ -15,7 +15,7 @@ type SubFrameOffsetData = { url: string; top: number; left: number; -}; +} | null; type SubFrameOffsetsForTab = Record< chrome.runtime.MessageSender["tab"]["id"], diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index f525e861e62..78a00fb22d2 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -42,6 +42,7 @@ import { WebsiteIconData, PageDetailsForTab, SubFrameOffsetsForTab, + SubFrameOffsetData, } from "./abstractions/overlay.background"; class OverlayBackground implements OverlayBackgroundInterface { @@ -112,12 +113,15 @@ class OverlayBackground implements OverlayBackgroundInterface { * @param tabId - Used to reference the page details of a specific tab */ removePageDetails(tabId: number) { - if (!this.pageDetailsForTab[tabId]) { - return; + if (this.pageDetailsForTab[tabId]) { + this.pageDetailsForTab[tabId].clear(); + delete this.pageDetailsForTab[tabId]; } - this.pageDetailsForTab[tabId].clear(); - delete this.pageDetailsForTab[tabId]; + if (this.subFrameOffsetsForTab[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) { - // NOT SURE I WANT THIS void this.buildSubFrameOffset(pageDetails); } @@ -226,13 +229,42 @@ class OverlayBackground implements OverlayBackgroundInterface { } private async buildSubFrameOffset({ tab, frameId, details }: PageDetail) { - const frameDetails = await BrowserApi.getFrameDetails({ - tabId: tab.id, - frameId, - }); + const tabId = tab.id; + let subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId]; + if (!subFrameOffsetsForTab) { + this.subFrameOffsetsForTab[tabId] = new Map(); + subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId]; + } - // eslint-disable-next-line - console.log(frameDetails); + if (subFrameOffsetsForTab.get(frameId)) { + 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); } /** diff --git a/apps/browser/src/autofill/content/abstractions/autofill-init.ts b/apps/browser/src/autofill/content/abstractions/autofill-init.ts index 91866ffa0bb..54765753261 100644 --- a/apps/browser/src/autofill/content/abstractions/autofill-init.ts +++ b/apps/browser/src/autofill/content/abstractions/autofill-init.ts @@ -1,5 +1,6 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { SubFrameOffsetData } from "../../background/abstractions/overlay.background"; import AutofillScript from "../../models/autofill-script"; type AutofillExtensionMessage = { @@ -8,6 +9,7 @@ type AutofillExtensionMessage = { sender?: string; fillScript?: AutofillScript; url?: string; + subFrameUrl?: string; pageDetailsUrl?: string; ciphers?: any; data?: { @@ -36,6 +38,7 @@ type AutofillExtensionMessageHandlers = { bgUnlockPopoutOpened: () => void; bgVaultItemRepromptPopoutOpened: () => void; updateAutofillOverlayVisibility: ({ message }: AutofillExtensionMessageParam) => void; + getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise; }; interface AutofillInit { diff --git a/apps/browser/src/autofill/content/autofill-init.ts b/apps/browser/src/autofill/content/autofill-init.ts index 15904fa79f9..52946b95b7c 100644 --- a/apps/browser/src/autofill/content/autofill-init.ts +++ b/apps/browser/src/autofill/content/autofill-init.ts @@ -1,3 +1,4 @@ +import { SubFrameOffsetData } from "../background/abstractions/overlay.background"; import AutofillPageDetails from "../models/autofill-page-details"; import { AutofillOverlayContentService } from "../services/abstractions/autofill-overlay-content.service"; import CollectAutofillContentService from "../services/collect-autofill-content.service"; @@ -28,7 +29,7 @@ class AutofillInit implements AutofillInitInterface { bgUnlockPopoutOpened: () => this.blurAndRemoveOverlay(), bgVaultItemRepromptPopoutOpened: () => this.blurAndRemoveOverlay(), 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; } - private getSubFrameOffsets() {} + private async getSubFrameOffsets( + message: AutofillExtensionMessage, + ): Promise { + 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. diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts index dc834201771..e93a4573a5c 100644 --- a/apps/browser/src/platform/browser/browser-api.ts +++ b/apps/browser/src/platform/browser/browser-api.ts @@ -178,17 +178,17 @@ export class BrowserApi { tab: chrome.tabs.Tab, obj: T, options: chrome.tabs.MessageSendOptions = null, - ): Promise { + ): Promise { if (!tab || !tab.id) { return; } - return new Promise((resolve) => { - chrome.tabs.sendMessage(tab.id, obj, options, () => { + return new Promise((resolve) => { + chrome.tabs.sendMessage(tab.id, obj, options, (response) => { if (chrome.runtime.lastError) { // Some error happened } - resolve(); + resolve(response); }); }); }