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:
@@ -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"],
|
||||||
|
|||||||
@@ -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,14 +113,17 @@ 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();
|
this.pageDetailsForTab[tabId].clear();
|
||||||
delete this.pageDetailsForTab[tabId];
|
delete this.pageDetailsForTab[tabId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.subFrameOffsetsForTab[tabId]) {
|
||||||
|
this.subFrameOffsetsForTab[tabId].clear();
|
||||||
|
delete this.subFrameOffsetsForTab[tabId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the extension message listeners and gets the settings for the
|
* Sets up the extension message listeners and gets the settings for the
|
||||||
* overlay's visibility and the user's authentication status.
|
* overlay's visibility and the user's authentication status.
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user