1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 00:33:44 +00:00

[PM-5189] Implementing a set threshold for the maximum depth for which we are willing to calculate sub frame offsets

This commit is contained in:
Cesar Gonzalez
2024-06-12 16:29:55 -05:00
parent b1e75ad7b5
commit b857e4943a
5 changed files with 71 additions and 13 deletions

View File

@@ -121,6 +121,10 @@ export type OverlayBackgroundExtensionMessageHandlers = {
getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number; getCurrentTabFrameId: ({ sender }: BackgroundSenderParam) => number;
updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; updateSubFrameData: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void; rebuildSubFrameOffsets: ({ sender }: BackgroundSenderParam) => void;
destroyAutofillInlineMenuListeners: ({
message,
sender,
}: BackgroundOnMessageHandlerParams) => void;
collectPageDetailsResponse: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; collectPageDetailsResponse: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
unlockCompleted: ({ message }: BackgroundMessageParam) => void; unlockCompleted: ({ message }: BackgroundMessageParam) => void;
addedCipher: () => void; addedCipher: () => void;

View File

@@ -25,7 +25,11 @@ import {
openAddEditVaultItemPopout, openAddEditVaultItemPopout,
openViewVaultItemPopout, openViewVaultItemPopout,
} from "../../vault/popup/utils/vault-popout-window"; } from "../../vault/popup/utils/vault-popout-window";
import { AutofillOverlayElement, AutofillOverlayPort } from "../enums/autofill-overlay.enum"; import {
AutofillOverlayElement,
AutofillOverlayPort,
MAX_SUB_FRAME_DEPTH,
} from "../enums/autofill-overlay.enum";
import { AutofillService } from "../services/abstractions/autofill.service"; import { AutofillService } from "../services/abstractions/autofill.service";
import { generateRandomChars } from "../utils"; import { generateRandomChars } from "../utils";
@@ -92,6 +96,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender), getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender),
updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender), updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender),
rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender), rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender),
destroyAutofillInlineMenuListeners: ({ message, sender }) =>
this.triggerDestroyInlineMenuListeners(sender.tab, message.subFrameData.frameId),
collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender), collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender),
unlockCompleted: ({ message }) => this.unlockCompleted(message), unlockCompleted: ({ message }) => this.unlockCompleted(message),
addedCipher: () => this.updateInlineMenuCiphers(), addedCipher: () => this.updateInlineMenuCiphers(),
@@ -293,6 +299,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* @param url - The URL of the sub frame * @param url - The URL of the sub frame
*/ */
private async buildSubFrameOffsets(tab: chrome.tabs.Tab, frameId: number, url: string) { private async buildSubFrameOffsets(tab: chrome.tabs.Tab, frameId: number, url: string) {
let subFrameDepth = 0;
const tabId = tab.id; const tabId = tab.id;
let subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId]; let subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId];
if (!subFrameOffsetsForTab) { if (!subFrameOffsetsForTab) {
@@ -307,7 +314,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
const subFrameData: SubFrameOffsetData = { url, top: 0, left: 0, parentFrameIds: [] }; const subFrameData: SubFrameOffsetData = { url, top: 0, left: 0, parentFrameIds: [] };
let frameDetails = await BrowserApi.getFrameDetails({ tabId, frameId }); let frameDetails = await BrowserApi.getFrameDetails({ tabId, frameId });
while (frameDetails && frameDetails.parentFrameId > -1) { while (
(frameDetails && frameDetails.parentFrameId > -1) ||
subFrameDepth > MAX_SUB_FRAME_DEPTH
) {
const subFrameOffset: SubFrameOffsetData = await BrowserApi.tabSendMessage( const subFrameOffset: SubFrameOffsetData = await BrowserApi.tabSendMessage(
tab, tab,
{ {
@@ -323,7 +333,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
void BrowserApi.tabSendMessage( void BrowserApi.tabSendMessage(
tab, tab,
{ command: "getSubFrameOffsetsFromWindowMessage", subFrameId: frameId }, { command: "getSubFrameOffsetsFromWindowMessage", subFrameId: frameId },
{ frameId: frameId }, { frameId },
); );
return; return;
} }
@@ -336,11 +346,38 @@ export class OverlayBackground implements OverlayBackgroundInterface {
tabId, tabId,
frameId: frameDetails.parentFrameId, frameId: frameDetails.parentFrameId,
}); });
subFrameDepth++;
}
if (subFrameDepth > MAX_SUB_FRAME_DEPTH) {
subFrameOffsetsForTab.set(frameId, null);
this.triggerDestroyInlineMenuListeners(tab, frameId);
return;
} }
subFrameOffsetsForTab.set(frameId, subFrameData); subFrameOffsetsForTab.set(frameId, subFrameData);
} }
/**
* Triggers a removal and destruction of all
*
* @param tab - The tab that the sub frame is associated with
* @param frameId - The frame ID of the sub frame
*/
private triggerDestroyInlineMenuListeners(tab: chrome.tabs.Tab, frameId: number) {
this.logService.error(
"Excessive frame depth encountered, destroying inline menu on field within frame",
tab,
frameId,
);
void BrowserApi.tabSendMessage(
tab,
{ command: "destroyAutofillInlineMenuListeners" },
{ frameId },
);
}
/** /**
* Handles rebuilding the sub frame offsets when the tab is repositioned or scrolled. * Handles rebuilding the sub frame offsets when the tab is repositioned or scrolled.
* Will trigger a re-positioning of the inline menu list and button. Note that we * Will trigger a re-positioning of the inline menu list and button. Note that we

View File

@@ -1,19 +1,19 @@
const AutofillOverlayElement = { export const AutofillOverlayElement = {
Button: "autofill-inline-menu-button", Button: "autofill-inline-menu-button",
List: "autofill-inline-menu-list", List: "autofill-inline-menu-list",
} as const; } as const;
const AutofillOverlayPort = { export const AutofillOverlayPort = {
Button: "autofill-inline-menu-button-port", Button: "autofill-inline-menu-button-port",
ButtonMessageConnector: "autofill-inline-menu-button-message-connector", ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
List: "autofill-inline-menu-list-port", List: "autofill-inline-menu-list-port",
ListMessageConnector: "autofill-inline-menu-list-message-connector", ListMessageConnector: "autofill-inline-menu-list-message-connector",
} as const; } as const;
const RedirectFocusDirection = { export const RedirectFocusDirection = {
Current: "current", Current: "current",
Previous: "previous", Previous: "previous",
Next: "next", Next: "next",
} as const; } as const;
export { AutofillOverlayElement, AutofillOverlayPort, RedirectFocusDirection }; export const MAX_SUB_FRAME_DEPTH = 10;

View File

@@ -11,6 +11,10 @@ export type OpenAutofillInlineMenuOptions = {
authStatus?: AuthenticationStatus; authStatus?: AuthenticationStatus;
}; };
export type SubFrameDataFromWindowMessage = SubFrameOffsetData & {
subFrameDepth: number;
};
export type AutofillOverlayContentExtensionMessageHandlers = { export type AutofillOverlayContentExtensionMessageHandlers = {
[key: string]: CallableFunction; [key: string]: CallableFunction;
openAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void; openAutofillInlineMenu: ({ message }: AutofillExtensionMessageParam) => void;
@@ -24,6 +28,7 @@ export type AutofillOverlayContentExtensionMessageHandlers = {
getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise<SubFrameOffsetData>; getSubFrameOffsets: ({ message }: AutofillExtensionMessageParam) => Promise<SubFrameOffsetData>;
getSubFrameOffsetsFromWindowMessage: ({ message }: AutofillExtensionMessageParam) => void; getSubFrameOffsetsFromWindowMessage: ({ message }: AutofillExtensionMessageParam) => void;
checkMostRecentlyFocusedFieldHasValue: () => boolean; checkMostRecentlyFocusedFieldHasValue: () => boolean;
destroyAutofillInlineMenuListeners: () => void;
}; };
export interface AutofillOverlayContentService { export interface AutofillOverlayContentService {

View File

@@ -10,7 +10,11 @@ import {
SubFrameOffsetData, SubFrameOffsetData,
} from "../background/abstractions/overlay.background"; } from "../background/abstractions/overlay.background";
import { AutofillExtensionMessage } from "../content/abstractions/autofill-init"; import { AutofillExtensionMessage } from "../content/abstractions/autofill-init";
import { AutofillOverlayElement, RedirectFocusDirection } from "../enums/autofill-overlay.enum"; import {
AutofillOverlayElement,
MAX_SUB_FRAME_DEPTH,
RedirectFocusDirection,
} from "../enums/autofill-overlay.enum";
import AutofillField from "../models/autofill-field"; import AutofillField from "../models/autofill-field";
import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types"; import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types";
import { elementIsFillableFormField, getAttributeBoolean, sendExtensionMessage } from "../utils"; import { elementIsFillableFormField, getAttributeBoolean, sendExtensionMessage } from "../utils";
@@ -19,6 +23,7 @@ import {
AutofillOverlayContentExtensionMessageHandlers, AutofillOverlayContentExtensionMessageHandlers,
AutofillOverlayContentService as AutofillOverlayContentServiceInterface, AutofillOverlayContentService as AutofillOverlayContentServiceInterface,
OpenAutofillInlineMenuOptions, OpenAutofillInlineMenuOptions,
SubFrameDataFromWindowMessage,
} from "./abstractions/autofill-overlay-content.service"; } from "./abstractions/autofill-overlay-content.service";
import { AutoFillConstants } from "./autofill-constants"; import { AutoFillConstants } from "./autofill-constants";
@@ -54,6 +59,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
getSubFrameOffsetsFromWindowMessage: ({ message }) => getSubFrameOffsetsFromWindowMessage: ({ message }) =>
this.getSubFrameOffsetsFromWindowMessage(message), this.getSubFrameOffsetsFromWindowMessage(message),
checkMostRecentlyFocusedFieldHasValue: () => this.mostRecentlyFocusedFieldHasValue(), checkMostRecentlyFocusedFieldHasValue: () => this.mostRecentlyFocusedFieldHasValue(),
destroyAutofillInlineMenuListeners: () => this.destroy(),
}; };
/** /**
@@ -1025,7 +1031,8 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
left: 0, left: 0,
top: 0, top: 0,
parentFrameIds: [], parentFrameIds: [],
}, subFrameDepth: 0,
} as SubFrameDataFromWindowMessage,
}, },
"*", "*",
); );
@@ -1050,7 +1057,14 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
* @param event - The message event. * @param event - The message event.
*/ */
private calculateSubFramePositioning = async (event: MessageEvent) => { private calculateSubFramePositioning = async (event: MessageEvent) => {
const subFrameData = event.data.subFrameData; const subFrameData: SubFrameDataFromWindowMessage = event.data.subFrameData;
subFrameData.subFrameDepth++;
if (subFrameData.subFrameDepth > MAX_SUB_FRAME_DEPTH) {
void this.sendExtensionMessage("destroyAutofillInlineMenuListeners", { subFrameData });
return;
}
let subFrameOffsets: SubFrameOffsetData; let subFrameOffsets: SubFrameOffsetData;
const iframes = globalThis.document.querySelectorAll("iframe"); const iframes = globalThis.document.querySelectorAll("iframe");
for (let i = 0; i < iframes.length; i++) { for (let i = 0; i < iframes.length; i++) {
@@ -1079,9 +1093,7 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
return; return;
} }
void this.sendExtensionMessage("updateSubFrameData", { void this.sendExtensionMessage("updateSubFrameData", { subFrameData });
subFrameData,
});
}; };
/** /**