1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-01-24 21:41:33 +01: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
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
5 changed files with 71 additions and 13 deletions

View File

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

View File

@ -25,7 +25,11 @@ import {
openAddEditVaultItemPopout,
openViewVaultItemPopout,
} 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 { generateRandomChars } from "../utils";
@ -92,6 +96,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
getCurrentTabFrameId: ({ sender }) => this.getSenderFrameId(sender),
updateSubFrameData: ({ message, sender }) => this.updateSubFrameData(message, sender),
rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender),
destroyAutofillInlineMenuListeners: ({ message, sender }) =>
this.triggerDestroyInlineMenuListeners(sender.tab, message.subFrameData.frameId),
collectPageDetailsResponse: ({ message, sender }) => this.storePageDetails(message, sender),
unlockCompleted: ({ message }) => this.unlockCompleted(message),
addedCipher: () => this.updateInlineMenuCiphers(),
@ -293,6 +299,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* @param url - The URL of the sub frame
*/
private async buildSubFrameOffsets(tab: chrome.tabs.Tab, frameId: number, url: string) {
let subFrameDepth = 0;
const tabId = tab.id;
let subFrameOffsetsForTab = this.subFrameOffsetsForTab[tabId];
if (!subFrameOffsetsForTab) {
@ -307,7 +314,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
const subFrameData: SubFrameOffsetData = { url, top: 0, left: 0, parentFrameIds: [] };
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(
tab,
{
@ -323,7 +333,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
void BrowserApi.tabSendMessage(
tab,
{ command: "getSubFrameOffsetsFromWindowMessage", subFrameId: frameId },
{ frameId: frameId },
{ frameId },
);
return;
}
@ -336,11 +346,38 @@ export class OverlayBackground implements OverlayBackgroundInterface {
tabId,
frameId: frameDetails.parentFrameId,
});
subFrameDepth++;
}
if (subFrameDepth > MAX_SUB_FRAME_DEPTH) {
subFrameOffsetsForTab.set(frameId, null);
this.triggerDestroyInlineMenuListeners(tab, frameId);
return;
}
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.
* 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",
List: "autofill-inline-menu-list",
} as const;
const AutofillOverlayPort = {
export const AutofillOverlayPort = {
Button: "autofill-inline-menu-button-port",
ButtonMessageConnector: "autofill-inline-menu-button-message-connector",
List: "autofill-inline-menu-list-port",
ListMessageConnector: "autofill-inline-menu-list-message-connector",
} as const;
const RedirectFocusDirection = {
export const RedirectFocusDirection = {
Current: "current",
Previous: "previous",
Next: "next",
} as const;
export { AutofillOverlayElement, AutofillOverlayPort, RedirectFocusDirection };
export const MAX_SUB_FRAME_DEPTH = 10;

View File

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

View File

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