1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

[PM-6921] Optimize methodology for storing page details within inline menu background processes (#8385)

* [PM-6921] Optimize methodology for storing page details within inline menu background processes

* [PM-6921] Incorporating method for ensuring that we clear the Map datastructure when the page details are being removed

* [PM-6921] Adjusting method to ensure that page details always remain up to date for when processed
This commit is contained in:
Cesar Gonzalez
2024-03-21 12:41:26 -05:00
committed by GitHub
parent 600cc080b8
commit b9f9ad029f
2 changed files with 76 additions and 23 deletions

View File

@@ -125,7 +125,8 @@ describe("OverlayBackground", () => {
describe("removePageDetails", () => { describe("removePageDetails", () => {
it("removes the page details for a specific tab from the pageDetailsForTab object", () => { it("removes the page details for a specific tab from the pageDetailsForTab object", () => {
const tabId = 1; const tabId = 1;
overlayBackground["pageDetailsForTab"][tabId] = [createPageDetailMock()]; const frameId = 2;
overlayBackground["pageDetailsForTab"][tabId] = new Map([[frameId, createPageDetailMock()]]);
overlayBackground.removePageDetails(tabId); overlayBackground.removePageDetails(tabId);
expect(overlayBackground["pageDetailsForTab"][tabId]).toBeUndefined(); expect(overlayBackground["pageDetailsForTab"][tabId]).toBeUndefined();
@@ -864,29 +865,40 @@ describe("OverlayBackground", () => {
sender, sender,
); );
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual([ expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual(
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }, new Map([
]); [sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
]),
);
}); });
it("updates the page details for a tab that already has a set of page details stored ", () => { it("updates the page details for a tab that already has a set of page details stored ", () => {
overlayBackground["pageDetailsForTab"][sender.tab.id] = [ const secondFrameSender = mock<chrome.runtime.MessageSender>({
{ tab: { id: 1 },
frameId: sender.frameId, frameId: 3,
tab: sender.tab, });
details: pageDetails1, overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
}, [sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
]; ]);
sendExtensionRuntimeMessage( sendExtensionRuntimeMessage(
{ command: "collectPageDetailsResponse", details: pageDetails2 }, { command: "collectPageDetailsResponse", details: pageDetails2 },
sender, secondFrameSender,
); );
expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual([ expect(overlayBackground["pageDetailsForTab"][sender.tab.id]).toStrictEqual(
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }, new Map([
{ frameId: sender.frameId, tab: sender.tab, details: pageDetails2 }, [sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails1 }],
]); [
secondFrameSender.frameId,
{
frameId: secondFrameSender.frameId,
tab: secondFrameSender.tab,
details: pageDetails2,
},
],
]),
);
}); });
}); });
@@ -1196,6 +1208,10 @@ describe("OverlayBackground", () => {
let getLoginCiphersSpy: jest.SpyInstance; let getLoginCiphersSpy: jest.SpyInstance;
let isPasswordRepromptRequiredSpy: jest.SpyInstance; let isPasswordRepromptRequiredSpy: jest.SpyInstance;
let doAutoFillSpy: jest.SpyInstance; let doAutoFillSpy: jest.SpyInstance;
let sender: chrome.runtime.MessageSender;
const pageDetails = createAutofillPageDetailsMock({
login: { username: "username1", password: "password1" },
});
beforeEach(() => { beforeEach(() => {
getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get"); getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get");
@@ -1204,6 +1220,7 @@ describe("OverlayBackground", () => {
"isPasswordRepromptRequired", "isPasswordRepromptRequired",
); );
doAutoFillSpy = jest.spyOn(overlayBackground["autofillService"], "doAutoFill"); doAutoFillSpy = jest.spyOn(overlayBackground["autofillService"], "doAutoFill");
sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
}); });
it("ignores the fill request if the overlay cipher id is not provided", async () => { it("ignores the fill request if the overlay cipher id is not provided", async () => {
@@ -1215,12 +1232,27 @@ describe("OverlayBackground", () => {
expect(doAutoFillSpy).not.toHaveBeenCalled(); expect(doAutoFillSpy).not.toHaveBeenCalled();
}); });
it("ignores the fill request if the tab does not contain any identified page details", async () => {
sendPortMessage(listPortSpy, {
command: "fillSelectedListItem",
overlayCipherId: "overlay-cipher-1",
});
await flushPromises();
expect(getLoginCiphersSpy).not.toHaveBeenCalled();
expect(isPasswordRepromptRequiredSpy).not.toHaveBeenCalled();
expect(doAutoFillSpy).not.toHaveBeenCalled();
});
it("ignores the fill request if a master password reprompt is required", async () => { it("ignores the fill request if a master password reprompt is required", async () => {
const cipher = mock<CipherView>({ const cipher = mock<CipherView>({
reprompt: CipherRepromptType.Password, reprompt: CipherRepromptType.Password,
type: CipherType.Login, type: CipherType.Login,
}); });
overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher]]); overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]);
getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get"); getLoginCiphersSpy = jest.spyOn(overlayBackground["overlayLoginCiphers"], "get");
isPasswordRepromptRequiredSpy.mockResolvedValue(true); isPasswordRepromptRequiredSpy.mockResolvedValue(true);
@@ -1247,6 +1279,14 @@ describe("OverlayBackground", () => {
["overlay-cipher-2", cipher2], ["overlay-cipher-2", cipher2],
["overlay-cipher-3", cipher3], ["overlay-cipher-3", cipher3],
]); ]);
const pageDetailsForTab = {
frameId: sender.frameId,
tab: sender.tab,
details: pageDetails,
};
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, pageDetailsForTab],
]);
isPasswordRepromptRequiredSpy.mockResolvedValue(false); isPasswordRepromptRequiredSpy.mockResolvedValue(false);
sendPortMessage(listPortSpy, { sendPortMessage(listPortSpy, {
@@ -1262,7 +1302,7 @@ describe("OverlayBackground", () => {
expect(doAutoFillSpy).toHaveBeenCalledWith({ expect(doAutoFillSpy).toHaveBeenCalledWith({
tab: listPortSpy.sender.tab, tab: listPortSpy.sender.tab,
cipher: cipher2, cipher: cipher2,
pageDetails: undefined, pageDetails: [pageDetailsForTab],
fillNewPassword: true, fillNewPassword: true,
allowTotpAutofill: true, allowTotpAutofill: true,
}); });
@@ -1278,6 +1318,9 @@ describe("OverlayBackground", () => {
it("copies the cipher's totp code to the clipboard after filling", async () => { it("copies the cipher's totp code to the clipboard after filling", async () => {
const cipher1 = mock<CipherView>({ id: "overlay-cipher-1" }); const cipher1 = mock<CipherView>({ id: "overlay-cipher-1" });
overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher1]]); overlayBackground["overlayLoginCiphers"] = new Map([["overlay-cipher-1", cipher1]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]);
isPasswordRepromptRequiredSpy.mockResolvedValue(false); isPasswordRepromptRequiredSpy.mockResolvedValue(false);
const copyToClipboardSpy = jest const copyToClipboardSpy = jest
.spyOn(overlayBackground["platformUtilsService"], "copyToClipboard") .spyOn(overlayBackground["platformUtilsService"], "copyToClipboard")

View File

@@ -47,7 +47,10 @@ class OverlayBackground implements OverlayBackgroundInterface {
private readonly openViewVaultItemPopout = openViewVaultItemPopout; private readonly openViewVaultItemPopout = openViewVaultItemPopout;
private readonly openAddEditVaultItemPopout = openAddEditVaultItemPopout; private readonly openAddEditVaultItemPopout = openAddEditVaultItemPopout;
private overlayLoginCiphers: Map<string, CipherView> = new Map(); private overlayLoginCiphers: Map<string, CipherView> = new Map();
private pageDetailsForTab: Record<number, PageDetail[]> = {}; private pageDetailsForTab: Record<
chrome.runtime.MessageSender["tab"]["id"],
Map<chrome.runtime.MessageSender["frameId"], PageDetail>
> = {};
private userAuthStatus: AuthenticationStatus = AuthenticationStatus.LoggedOut; private userAuthStatus: AuthenticationStatus = AuthenticationStatus.LoggedOut;
private overlayButtonPort: chrome.runtime.Port; private overlayButtonPort: chrome.runtime.Port;
private overlayListPort: chrome.runtime.Port; private overlayListPort: chrome.runtime.Port;
@@ -107,6 +110,11 @@ 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]) {
return;
}
this.pageDetailsForTab[tabId].clear();
delete this.pageDetailsForTab[tabId]; delete this.pageDetailsForTab[tabId];
} }
@@ -203,12 +211,13 @@ class OverlayBackground implements OverlayBackgroundInterface {
details: message.details, details: message.details,
}; };
if (this.pageDetailsForTab[sender.tab.id]?.length) { const pageDetailsMap = this.pageDetailsForTab[sender.tab.id];
this.pageDetailsForTab[sender.tab.id].push(pageDetails); if (!pageDetailsMap) {
this.pageDetailsForTab[sender.tab.id] = new Map([[sender.frameId, pageDetails]]);
return; return;
} }
this.pageDetailsForTab[sender.tab.id] = [pageDetails]; pageDetailsMap.set(sender.frameId, pageDetails);
} }
/** /**
@@ -222,7 +231,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
{ overlayCipherId }: OverlayPortMessage, { overlayCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port, { sender }: chrome.runtime.Port,
) { ) {
if (!overlayCipherId) { const pageDetails = this.pageDetailsForTab[sender.tab.id];
if (!overlayCipherId || !pageDetails?.size) {
return; return;
} }
@@ -234,7 +244,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
const totpCode = await this.autofillService.doAutoFill({ const totpCode = await this.autofillService.doAutoFill({
tab: sender.tab, tab: sender.tab,
cipher: cipher, cipher: cipher,
pageDetails: this.pageDetailsForTab[sender.tab.id], pageDetails: Array.from(pageDetails.values()),
fillNewPassword: true, fillNewPassword: true,
allowTotpAutofill: true, allowTotpAutofill: true,
}); });