1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 01:03:35 +00:00

[PM-5189] Refactoring implementation

This commit is contained in:
Cesar Gonzalez
2024-06-07 09:29:25 -05:00
parent f34fbc217c
commit 0e33b9c215
13 changed files with 109 additions and 106 deletions

View File

@@ -73,10 +73,10 @@ export type OverlayPortMessage = {
[key: string]: any; [key: string]: any;
command: string; command: string;
direction?: string; direction?: string;
overlayCipherId?: string; inlineMenuCipherId?: string;
}; };
export type OverlayCipherData = { export type InlineMenuCipherData = {
id: string; id: string;
name: string; name: string;
type: CipherType; type: CipherType;
@@ -139,8 +139,8 @@ export type PortOnMessageHandlerParams = PortMessageParam & PortConnectionParam;
export type InlineMenuButtonPortMessageHandlers = { export type InlineMenuButtonPortMessageHandlers = {
[key: string]: CallableFunction; [key: string]: CallableFunction;
autofillInlineMenuButtonClicked: ({ port }: PortConnectionParam) => void;
triggerDelayedAutofillInlineMenuClosure: ({ port }: PortConnectionParam) => void; triggerDelayedAutofillInlineMenuClosure: ({ port }: PortConnectionParam) => void;
autofillInlineMenuButtonClicked: ({ port }: PortConnectionParam) => void;
autofillInlineMenuBlurred: () => void; autofillInlineMenuBlurred: () => void;
redirectAutofillInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void; redirectAutofillInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;
updateAutofillInlineMenuColorScheme: () => void; updateAutofillInlineMenuColorScheme: () => void;
@@ -161,5 +161,5 @@ export type InlineMenuListPortMessageHandlers = {
export interface OverlayBackground { export interface OverlayBackground {
init(): Promise<void>; init(): Promise<void>;
removePageDetails(tabId: number): void; removePageDetails(tabId: number): void;
updateOverlayCiphers(): void; updateInlineMenuCiphers(): void;
} }

View File

@@ -512,7 +512,7 @@ describe("OverlayBackground", () => {
it("skips updating the overlay ciphers if the user's auth status is not unlocked", async () => { it("skips updating the overlay ciphers if the user's auth status is not unlocked", async () => {
activeAccountStatusMock$.next(AuthenticationStatus.Locked); activeAccountStatusMock$.next(AuthenticationStatus.Locked);
await overlayBackground.updateOverlayCiphers(); await overlayBackground.updateInlineMenuCiphers();
expect(getTabFromCurrentWindowIdSpy).not.toHaveBeenCalled(); expect(getTabFromCurrentWindowIdSpy).not.toHaveBeenCalled();
expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled(); expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled();
@@ -521,7 +521,7 @@ describe("OverlayBackground", () => {
it("ignores updating the overlay ciphers if the tab is undefined", async () => { it("ignores updating the overlay ciphers if the tab is undefined", async () => {
getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(undefined); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(undefined);
await overlayBackground.updateOverlayCiphers(); await overlayBackground.updateInlineMenuCiphers();
expect(getTabFromCurrentWindowIdSpy).toHaveBeenCalled(); expect(getTabFromCurrentWindowIdSpy).toHaveBeenCalled();
expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled(); expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled();
@@ -532,26 +532,26 @@ describe("OverlayBackground", () => {
cipherService.getAllDecryptedForUrl.mockResolvedValue([cipher1, cipher2]); cipherService.getAllDecryptedForUrl.mockResolvedValue([cipher1, cipher2]);
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
await overlayBackground.updateOverlayCiphers(); await overlayBackground.updateInlineMenuCiphers();
expect(BrowserApi.getTabFromCurrentWindowId).toHaveBeenCalled(); expect(BrowserApi.getTabFromCurrentWindowId).toHaveBeenCalled();
expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith(url); expect(cipherService.getAllDecryptedForUrl).toHaveBeenCalledWith(url);
expect(cipherService.sortCiphersByLastUsedThenName).toHaveBeenCalled(); expect(cipherService.sortCiphersByLastUsedThenName).toHaveBeenCalled();
expect(overlayBackground["inlineMenuCiphers"]).toStrictEqual( expect(overlayBackground["inlineMenuCiphers"]).toStrictEqual(
new Map([ new Map([
["overlay-cipher-0", cipher2], ["inline-menu-cipher-0", cipher2],
["overlay-cipher-1", cipher1], ["inline-menu-cipher-1", cipher1],
]), ]),
); );
}); });
it("posts an `updateOverlayListCiphers` message to the overlay list port, and send a `updateIsOverlayCiphersPopulated` message to the tab indicating that the list of ciphers is populated", async () => { it("posts an `updateOverlayListCiphers` message to the overlay list port, and send a `updateAutofillInlineMenuListCiphers` message to the tab indicating that the list of ciphers is populated", async () => {
overlayBackground["inlineMenuListPort"] = mock<chrome.runtime.Port>(); overlayBackground["inlineMenuListPort"] = mock<chrome.runtime.Port>();
cipherService.getAllDecryptedForUrl.mockResolvedValue([cipher1, cipher2]); cipherService.getAllDecryptedForUrl.mockResolvedValue([cipher1, cipher2]);
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1); cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab);
await overlayBackground.updateOverlayCiphers(); await overlayBackground.updateInlineMenuCiphers();
expect(overlayBackground["inlineMenuListPort"].postMessage).toHaveBeenCalledWith({ expect(overlayBackground["inlineMenuListPort"].postMessage).toHaveBeenCalledWith({
command: "updateAutofillInlineMenuListCiphers", command: "updateAutofillInlineMenuListCiphers",
@@ -565,7 +565,7 @@ describe("OverlayBackground", () => {
image: undefined, image: undefined,
imageEnabled: true, imageEnabled: true,
}, },
id: "overlay-cipher-0", id: "inline-menu-cipher-0",
login: null, login: null,
name: "name-2", name: "name-2",
reprompt: cipher2.reprompt, reprompt: cipher2.reprompt,
@@ -580,7 +580,7 @@ describe("OverlayBackground", () => {
image: "https://icons.bitwarden.com//jest-testing-website.com/icon.png", image: "https://icons.bitwarden.com//jest-testing-website.com/icon.png",
imageEnabled: true, imageEnabled: true,
}, },
id: "overlay-cipher-1", id: "inline-menu-cipher-1",
login: { login: {
username: "username-1", username: "username-1",
}, },
@@ -705,7 +705,7 @@ describe("OverlayBackground", () => {
it("returns true if the overlay login ciphers are populated", async () => { it("returns true if the overlay login ciphers are populated", async () => {
overlayBackground["inlineMenuCiphers"] = new Map([ overlayBackground["inlineMenuCiphers"] = new Map([
["overlay-cipher-0", mock<CipherView>()], ["inline-menu-cipher-0", mock<CipherView>()],
]); ]);
sendMockExtensionMessage( sendMockExtensionMessage(
@@ -1334,10 +1334,10 @@ describe("OverlayBackground", () => {
}); });
describe("unlockCompleted", () => { describe("unlockCompleted", () => {
let updateOverlayCiphersSpy: jest.SpyInstance; let updateInlineMenuCiphersSpy: jest.SpyInstance;
beforeEach(async () => { beforeEach(async () => {
updateOverlayCiphersSpy = jest.spyOn(overlayBackground, "updateOverlayCiphers"); updateInlineMenuCiphersSpy = jest.spyOn(overlayBackground, "updateInlineMenuCiphers");
await initOverlayElementPorts(); await initOverlayElementPorts();
}); });
@@ -1352,15 +1352,15 @@ describe("OverlayBackground", () => {
}); });
it("updates the overlay ciphers", async () => { it("updates the overlay ciphers", async () => {
const updateOverlayCiphersSpy = jest.spyOn(overlayBackground, "updateOverlayCiphers"); const updateInlineMenuCiphersSpy = jest.spyOn(overlayBackground, "updateInlineMenuCiphers");
sendMockExtensionMessage({ command: "unlockCompleted" }); sendMockExtensionMessage({ command: "unlockCompleted" });
await flushPromises(); await flushPromises();
expect(updateOverlayCiphersSpy).toHaveBeenCalled(); expect(updateInlineMenuCiphersSpy).toHaveBeenCalled();
}); });
it("opens the inline menu if a retry command is present in the message", async () => { it("opens the inline menu if a retry command is present in the message", async () => {
updateOverlayCiphersSpy.mockImplementation(); updateInlineMenuCiphersSpy.mockImplementation();
getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(createChromeTabMock({ id: 1 })); getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(createChromeTabMock({ id: 1 }));
sendMockExtensionMessage({ sendMockExtensionMessage({
command: "unlockCompleted", command: "unlockCompleted",
@@ -1392,13 +1392,13 @@ describe("OverlayBackground", () => {
]; ];
beforeEach(() => { beforeEach(() => {
jest.spyOn(overlayBackground, "updateOverlayCiphers").mockImplementation(); jest.spyOn(overlayBackground, "updateInlineMenuCiphers").mockImplementation();
}); });
extensionMessages.forEach((message) => { extensionMessages.forEach((message) => {
it(`triggers an update of the overlay ciphers when the ${message} message is received`, () => { it(`triggers an update of the overlay ciphers when the ${message} message is received`, () => {
sendMockExtensionMessage({ command: message }); sendMockExtensionMessage({ command: message });
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).toHaveBeenCalled();
}); });
}); });
}); });
@@ -1640,7 +1640,7 @@ describe("OverlayBackground", () => {
it("ignores the fill request if the tab does not contain any identified page details", async () => { it("ignores the fill request if the tab does not contain any identified page details", async () => {
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "fillSelectedAutofillInlineMenuListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-1", inlineMenuCipherId: "inline-menu-cipher-1",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1654,7 +1654,7 @@ describe("OverlayBackground", () => {
reprompt: CipherRepromptType.Password, reprompt: CipherRepromptType.Password,
type: CipherType.Login, type: CipherType.Login,
}); });
overlayBackground["inlineMenuCiphers"] = new Map([["overlay-cipher-1", cipher]]); overlayBackground["inlineMenuCiphers"] = new Map([["inline-menu-cipher-1", cipher]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([ overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }], [sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]); ]);
@@ -1662,7 +1662,7 @@ describe("OverlayBackground", () => {
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "fillSelectedAutofillInlineMenuListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-1", inlineMenuCipherId: "inline-menu-cipher-1",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1672,13 +1672,13 @@ describe("OverlayBackground", () => {
}); });
it("auto-fills the selected cipher and move it to the top of the front of the ciphers map", async () => { it("auto-fills the selected cipher and move it to the top of the front of the ciphers map", async () => {
const cipher1 = mock<CipherView>({ id: "overlay-cipher-1" }); const cipher1 = mock<CipherView>({ id: "inline-menu-cipher-1" });
const cipher2 = mock<CipherView>({ id: "overlay-cipher-2" }); const cipher2 = mock<CipherView>({ id: "inline-menu-cipher-2" });
const cipher3 = mock<CipherView>({ id: "overlay-cipher-3" }); const cipher3 = mock<CipherView>({ id: "inline-menu-cipher-3" });
overlayBackground["inlineMenuCiphers"] = new Map([ overlayBackground["inlineMenuCiphers"] = new Map([
["overlay-cipher-1", cipher1], ["inline-menu-cipher-1", cipher1],
["overlay-cipher-2", cipher2], ["inline-menu-cipher-2", cipher2],
["overlay-cipher-3", cipher3], ["inline-menu-cipher-3", cipher3],
]); ]);
const pageDetailsForTab = { const pageDetailsForTab = {
frameId: sender.frameId, frameId: sender.frameId,
@@ -1692,7 +1692,7 @@ describe("OverlayBackground", () => {
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "fillSelectedAutofillInlineMenuListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-2", inlineMenuCipherId: "inline-menu-cipher-2",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1710,16 +1710,16 @@ describe("OverlayBackground", () => {
}); });
expect(overlayBackground["inlineMenuCiphers"].entries()).toStrictEqual( expect(overlayBackground["inlineMenuCiphers"].entries()).toStrictEqual(
new Map([ new Map([
["overlay-cipher-2", cipher2], ["inline-menu-cipher-2", cipher2],
["overlay-cipher-1", cipher1], ["inline-menu-cipher-1", cipher1],
["overlay-cipher-3", cipher3], ["inline-menu-cipher-3", cipher3],
]).entries(), ]).entries(),
); );
}); });
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: "inline-menu-cipher-1" });
overlayBackground["inlineMenuCiphers"] = new Map([["overlay-cipher-1", cipher1]]); overlayBackground["inlineMenuCiphers"] = new Map([["inline-menu-cipher-1", cipher1]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([ overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
[sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }], [sender.frameId, { frameId: sender.frameId, tab: sender.tab, details: pageDetails }],
]); ]);
@@ -1731,7 +1731,7 @@ describe("OverlayBackground", () => {
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "fillSelectedAutofillInlineMenuListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-2", inlineMenuCipherId: "inline-menu-cipher-2",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1779,12 +1779,12 @@ describe("OverlayBackground", () => {
it("returns early if the passed cipher ID does not match one of the inline menu ciphers", async () => { it("returns early if the passed cipher ID does not match one of the inline menu ciphers", async () => {
overlayBackground["inlineMenuCiphers"] = new Map([ overlayBackground["inlineMenuCiphers"] = new Map([
["overlay-cipher-0", mock<CipherView>({ id: "overlay-cipher-0" })], ["inline-menu-cipher-0", mock<CipherView>({ id: "inline-menu-cipher-0" })],
]); ]);
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "viewSelectedCipher", command: "viewSelectedCipher",
overlayCipherId: "overlay-cipher-1", inlineMenuCipherId: "inline-menu-cipher-1",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1793,15 +1793,15 @@ describe("OverlayBackground", () => {
}); });
it("will open the view vault item popout with the selected cipher", async () => { it("will open the view vault item popout with the selected cipher", async () => {
const cipher = mock<CipherView>({ id: "overlay-cipher-1" }); const cipher = mock<CipherView>({ id: "inline-menu-cipher-1" });
overlayBackground["inlineMenuCiphers"] = new Map([ overlayBackground["inlineMenuCiphers"] = new Map([
["overlay-cipher-0", mock<CipherView>({ id: "overlay-cipher-0" })], ["inline-menu-cipher-0", mock<CipherView>({ id: "inline-menu-cipher-0" })],
["overlay-cipher-1", cipher], ["inline-menu-cipher-1", cipher],
]); ]);
sendPortMessage(listMessageConnectorSpy, { sendPortMessage(listMessageConnectorSpy, {
command: "viewSelectedCipher", command: "viewSelectedCipher",
overlayCipherId: "overlay-cipher-1", inlineMenuCipherId: "inline-menu-cipher-1",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();

View File

@@ -37,7 +37,7 @@ import {
OverlayBackgroundExtensionMessage, OverlayBackgroundExtensionMessage,
OverlayBackgroundExtensionMessageHandlers, OverlayBackgroundExtensionMessageHandlers,
InlineMenuButtonPortMessageHandlers, InlineMenuButtonPortMessageHandlers,
OverlayCipherData, InlineMenuCipherData,
InlineMenuListPortMessageHandlers, InlineMenuListPortMessageHandlers,
OverlayPortMessage, OverlayPortMessage,
PageDetailsForTab, PageDetailsForTab,
@@ -94,15 +94,15 @@ export class OverlayBackground implements OverlayBackgroundInterface {
rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender), rebuildSubFrameOffsets: ({ sender }) => this.rebuildSubFrameOffsets(sender),
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.updateOverlayCiphers(), addedCipher: () => this.updateInlineMenuCiphers(),
addEditCipherSubmitted: () => this.updateOverlayCiphers(), addEditCipherSubmitted: () => this.updateInlineMenuCiphers(),
editedCipher: () => this.updateOverlayCiphers(), editedCipher: () => this.updateInlineMenuCiphers(),
deletedCipher: () => this.updateOverlayCiphers(), deletedCipher: () => this.updateInlineMenuCiphers(),
}; };
private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = { private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = {
autofillInlineMenuButtonClicked: ({ port }) => this.handleInlineMenuButtonClicked(port),
triggerDelayedAutofillInlineMenuClosure: ({ port }) => triggerDelayedAutofillInlineMenuClosure: ({ port }) =>
this.triggerDelayedInlineMenuClosure(port.sender), this.triggerDelayedInlineMenuClosure(port.sender),
autofillInlineMenuButtonClicked: ({ port }) => this.handleInlineMenuButtonClicked(port),
autofillInlineMenuBlurred: () => this.checkInlineMenuListFocused(), autofillInlineMenuBlurred: () => this.checkInlineMenuListFocused(),
redirectAutofillInlineMenuFocusOut: ({ message, port }) => redirectAutofillInlineMenuFocusOut: ({ message, port }) =>
this.redirectInlineMenuFocusOut(message, port), this.redirectInlineMenuFocusOut(message, port),
@@ -171,7 +171,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* Queries all ciphers for the given url, and sorts them by last used. Will not update the * Queries all ciphers for the given url, and sorts them by last used. Will not update the
* list of ciphers if the extension is not unlocked. * list of ciphers if the extension is not unlocked.
*/ */
async updateOverlayCiphers() { async updateInlineMenuCiphers() {
const authStatus = await firstValueFrom(this.authService.activeAccountStatus$); const authStatus = await firstValueFrom(this.authService.activeAccountStatus$);
if (authStatus !== AuthenticationStatus.Unlocked) { if (authStatus !== AuthenticationStatus.Unlocked) {
return; return;
@@ -187,10 +187,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
(a, b) => this.cipherService.sortCiphersByLastUsedThenName(a, b), (a, b) => this.cipherService.sortCiphersByLastUsedThenName(a, b),
); );
for (let cipherIndex = 0; cipherIndex < ciphersViews.length; cipherIndex++) { for (let cipherIndex = 0; cipherIndex < ciphersViews.length; cipherIndex++) {
this.inlineMenuCiphers.set(`overlay-cipher-${cipherIndex}`, ciphersViews[cipherIndex]); this.inlineMenuCiphers.set(`inline-menu-cipher-${cipherIndex}`, ciphersViews[cipherIndex]);
} }
const ciphers = await this.getOverlayCipherData(); const ciphers = await this.getInlineMenuCipherData();
this.inlineMenuListPort?.postMessage({ this.inlineMenuListPort?.postMessage({
command: "updateAutofillInlineMenuListCiphers", command: "updateAutofillInlineMenuListCiphers",
ciphers, ciphers,
@@ -201,16 +201,16 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* Strips out unnecessary data from the ciphers and returns an array of * Strips out unnecessary data from the ciphers and returns an array of
* objects that contain the cipher data needed for the inline menu list. * objects that contain the cipher data needed for the inline menu list.
*/ */
private async getOverlayCipherData(): Promise<OverlayCipherData[]> { private async getInlineMenuCipherData(): Promise<InlineMenuCipherData[]> {
const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$); const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$);
const overlayCiphersArray = Array.from(this.inlineMenuCiphers); const inlineMenuCiphersArray = Array.from(this.inlineMenuCiphers);
const overlayCipherData: OverlayCipherData[] = []; const inlineMenuCipherData: InlineMenuCipherData[] = [];
for (let cipherIndex = 0; cipherIndex < overlayCiphersArray.length; cipherIndex++) { for (let cipherIndex = 0; cipherIndex < inlineMenuCiphersArray.length; cipherIndex++) {
const [overlayCipherId, cipher] = overlayCiphersArray[cipherIndex]; const [inlineMenuCipherId, cipher] = inlineMenuCiphersArray[cipherIndex];
overlayCipherData.push({ inlineMenuCipherData.push({
id: overlayCipherId, id: inlineMenuCipherId,
name: cipher.name, name: cipher.name,
type: cipher.type, type: cipher.type,
reprompt: cipher.reprompt, reprompt: cipher.reprompt,
@@ -221,7 +221,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
}); });
} }
return overlayCipherData; return inlineMenuCipherData;
} }
/** /**
@@ -414,19 +414,19 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* Triggers autofill for the selected cipher in the inline menu list. Also places * Triggers autofill for the selected cipher in the inline menu list. Also places
* the selected cipher at the top of the list of ciphers. * the selected cipher at the top of the list of ciphers.
* *
* @param overlayCipherId - Cipher ID corresponding to the inlineMenuCiphers map. Does not correspond to the actual cipher's ID. * @param inlineMenuCipherId - Cipher ID corresponding to the inlineMenuCiphers map. Does not correspond to the actual cipher's ID.
* @param sender - The sender of the port message * @param sender - The sender of the port message
*/ */
private async fillSelectedInlineMenuListItem( private async fillSelectedInlineMenuListItem(
{ overlayCipherId }: OverlayPortMessage, { inlineMenuCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port, { sender }: chrome.runtime.Port,
) { ) {
const pageDetails = this.pageDetailsForTab[sender.tab.id]; const pageDetails = this.pageDetailsForTab[sender.tab.id];
if (!overlayCipherId || !pageDetails?.size) { if (!inlineMenuCipherId || !pageDetails?.size) {
return; return;
} }
const cipher = this.inlineMenuCiphers.get(overlayCipherId); const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);
if (await this.autofillService.isPasswordRepromptRequired(cipher, sender.tab)) { if (await this.autofillService.isPasswordRepromptRequired(cipher, sender.tab)) {
return; return;
@@ -443,7 +443,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
this.platformUtilsService.copyToClipboard(totpCode); this.platformUtilsService.copyToClipboard(totpCode);
} }
this.inlineMenuCiphers = new Map([[overlayCipherId, cipher], ...this.inlineMenuCiphers]); this.inlineMenuCiphers = new Map([[inlineMenuCipherId, cipher], ...this.inlineMenuCiphers]);
} }
/** /**
@@ -814,14 +814,14 @@ export class OverlayBackground implements OverlayBackgroundInterface {
/** /**
* Triggers the opening of a vault item popout window associated * Triggers the opening of a vault item popout window associated
* with the passed cipher ID. * with the passed cipher ID.
* @param overlayCipherId - Cipher ID corresponding to the inlineMenuCiphers map. Does not correspond to the actual cipher's ID. * @param inlineMenuCipherId - Cipher ID corresponding to the inlineMenuCiphers map. Does not correspond to the actual cipher's ID.
* @param sender - The sender of the port message * @param sender - The sender of the port message
*/ */
private async viewSelectedCipher( private async viewSelectedCipher(
{ overlayCipherId }: OverlayPortMessage, { inlineMenuCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port, { sender }: chrome.runtime.Port,
) { ) {
const cipher = this.inlineMenuCiphers.get(overlayCipherId); const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);
if (!cipher) { if (!cipher) {
return; return;
} }
@@ -847,7 +847,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
*/ */
private async unlockCompleted(message: OverlayBackgroundExtensionMessage) { private async unlockCompleted(message: OverlayBackgroundExtensionMessage) {
await this.updateInlineMenuButtonAuthStatus(); await this.updateInlineMenuButtonAuthStatus();
await this.updateOverlayCiphers(); await this.updateInlineMenuCiphers();
if (message.data?.commandToRetry?.message?.command === "openAutofillInlineMenu") { if (message.data?.commandToRetry?.message?.command === "openAutofillInlineMenu") {
await this.openInlineMenu(true); await this.openInlineMenu(true);
@@ -1159,7 +1159,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
), ),
theme: await firstValueFrom(this.themeStateService.selectedTheme$), theme: await firstValueFrom(this.themeStateService.selectedTheme$),
translations: this.getInlineMenuTranslations(), translations: this.getInlineMenuTranslations(),
ciphers: isInlineMenuListPort ? await this.getOverlayCipherData() : null, ciphers: isInlineMenuListPort ? await this.getInlineMenuCipherData() : null,
portKey: this.portKeyForTab[port.sender.tab.id], portKey: this.portKeyForTab[port.sender.tab.id],
portName: isInlineMenuListPort portName: isInlineMenuListPort
? AutofillOverlayPort.ListMessageConnector ? AutofillOverlayPort.ListMessageConnector

View File

@@ -75,7 +75,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshBadge).toHaveBeenCalled();
expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).toHaveBeenCalled();
}); });
it("sends a `windowChanged` message", async () => { it("sends a `windowChanged` message", async () => {
@@ -93,7 +93,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshBadge).toHaveBeenCalled();
expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).toHaveBeenCalled();
}); });
it("sends a `tabChanged` message to the messaging service", async () => { it("sends a `tabChanged` message to the messaging service", async () => {
@@ -129,7 +129,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshBadge).toHaveBeenCalled();
expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).toHaveBeenCalled();
}); });
it("sends a `tabChanged` message to the messaging service", async () => { it("sends a `tabChanged` message to the messaging service", async () => {
@@ -173,7 +173,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled();
expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).not.toHaveBeenCalled();
}); });
it("skips updating the current tab data if the updated tab is not for the focusedWindowId", async () => { it("skips updating the current tab data if the updated tab is not for the focusedWindowId", async () => {
@@ -183,7 +183,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled();
expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).not.toHaveBeenCalled();
}); });
it("skips updating the current tab data if the updated tab is not active", async () => { it("skips updating the current tab data if the updated tab is not active", async () => {
@@ -193,7 +193,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).not.toHaveBeenCalled(); expect(mainBackground.refreshBadge).not.toHaveBeenCalled();
expect(mainBackground.refreshMenu).not.toHaveBeenCalled(); expect(mainBackground.refreshMenu).not.toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).not.toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).not.toHaveBeenCalled();
}); });
it("skips updating the badge, context menu and notification bar if the `onUpdatedRan` property of the main background class is set to `true`", async () => { it("skips updating the badge, context menu and notification bar if the `onUpdatedRan` property of the main background class is set to `true`", async () => {
@@ -218,7 +218,7 @@ describe("TabsBackground", () => {
expect(mainBackground.refreshBadge).toHaveBeenCalled(); expect(mainBackground.refreshBadge).toHaveBeenCalled();
expect(mainBackground.refreshMenu).toHaveBeenCalled(); expect(mainBackground.refreshMenu).toHaveBeenCalled();
expect(overlayBackground.updateOverlayCiphers).toHaveBeenCalled(); expect(overlayBackground.updateInlineMenuCiphers).toHaveBeenCalled();
}); });
it("sends a `tabChanged` message to the messaging service", async () => { it("sends a `tabChanged` message to the messaging service", async () => {

View File

@@ -99,7 +99,7 @@ export default class TabsBackground {
return; return;
} }
await this.overlayBackground.updateOverlayCiphers(); await this.overlayBackground.updateInlineMenuCiphers();
if (this.main.onUpdatedRan) { if (this.main.onUpdatedRan) {
return; return;
@@ -129,7 +129,7 @@ export default class TabsBackground {
await Promise.all([ await Promise.all([
this.main.refreshBadge(), this.main.refreshBadge(),
this.main.refreshMenu(), this.main.refreshMenu(),
this.overlayBackground.updateOverlayCiphers(), this.overlayBackground.updateInlineMenuCiphers(),
]); ]);
}; };
} }

View File

@@ -18,7 +18,6 @@ export type AutofillExtensionMessage = {
authStatus?: AuthenticationStatus; authStatus?: AuthenticationStatus;
isOpeningFullAutofillInlineMenu?: boolean; isOpeningFullAutofillInlineMenu?: boolean;
data?: { data?: {
isOverlayCiphersPopulated?: boolean;
direction?: "previous" | "next" | "current"; direction?: "previous" | "next" | "current";
forceCloseAutofillInlineMenu?: boolean; forceCloseAutofillInlineMenu?: boolean;
inlineMenuVisibility?: number; inlineMenuVisibility?: number;

View File

@@ -1,6 +1,6 @@
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { OverlayCipherData } from "../../../background/abstractions/overlay.background"; import { InlineMenuCipherData } from "../../../background/abstractions/overlay.background";
type AutofillInlineMenuMenuContainerMessage = { type AutofillInlineMenuMenuContainerMessage = {
command: string; command: string;
@@ -14,7 +14,7 @@ export type InitInlineMenuElementMessage = AutofillInlineMenuMenuContainerMessag
styleSheetUrl?: string; styleSheetUrl?: string;
theme?: string; theme?: string;
translations?: Record<string, string>; translations?: Record<string, string>;
ciphers?: OverlayCipherData[]; ciphers?: InlineMenuCipherData[];
portName?: string; portName?: string;
}; };

View File

@@ -1,11 +1,11 @@
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { OverlayCipherData } from "../../../background/abstractions/overlay.background"; import { InlineMenuCipherData } from "../../../background/abstractions/overlay.background";
type AutofillInlineMenuListMessage = { command: string }; type AutofillInlineMenuListMessage = { command: string };
export type UpdateAutofillInlineMenuListCiphersMessage = AutofillInlineMenuListMessage & { export type UpdateAutofillInlineMenuListCiphersMessage = AutofillInlineMenuListMessage & {
ciphers: OverlayCipherData[]; ciphers: InlineMenuCipherData[];
}; };
export type InitAutofillInlineMenuListMessage = AutofillInlineMenuListMessage & { export type InitAutofillInlineMenuListMessage = AutofillInlineMenuListMessage & {
@@ -13,7 +13,7 @@ export type InitAutofillInlineMenuListMessage = AutofillInlineMenuListMessage &
styleSheetUrl: string; styleSheetUrl: string;
theme: string; theme: string;
translations: Record<string, string>; translations: Record<string, string>;
ciphers?: OverlayCipherData[]; ciphers?: InlineMenuCipherData[];
portKey: string; portKey: string;
}; };

View File

@@ -8,6 +8,6 @@ export type AutofillInlineMenuPageElementWindowMessageHandlers =
export type AutofillInlineMenuPageElementWindowMessage = { export type AutofillInlineMenuPageElementWindowMessage = {
[key: string]: any; [key: string]: any;
command: string; command: string;
overlayCipherId?: string; inlineMenuCipherId?: string;
height?: number; height?: number;
}; };

View File

@@ -140,7 +140,7 @@ describe("AutofillInlineMenuList", () => {
fillCipherButton.dispatchEvent(new Event("click")); fillCipherButton.dispatchEvent(new Event("click"));
expect(globalThis.parent.postMessage).toHaveBeenCalledWith( expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "fillSelectedAutofillInlineMenuListItem", overlayCipherId: "1", portKey }, { command: "fillSelectedAutofillInlineMenuListItem", inlineMenuCipherId: "1", portKey },
"*", "*",
); );
}); });
@@ -236,7 +236,7 @@ describe("AutofillInlineMenuList", () => {
viewCipherButton.dispatchEvent(new Event("click")); viewCipherButton.dispatchEvent(new Event("click"));
expect(globalThis.parent.postMessage).toHaveBeenCalledWith( expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "viewSelectedCipher", overlayCipherId: "1", portKey }, { command: "viewSelectedCipher", inlineMenuCipherId: "1", portKey },
"*", "*",
); );
}); });

View File

@@ -3,7 +3,7 @@ import "lit/polyfill-support.js";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { EVENTS } from "@bitwarden/common/autofill/constants"; import { EVENTS } from "@bitwarden/common/autofill/constants";
import { OverlayCipherData } from "../../../../background/abstractions/overlay.background"; import { InlineMenuCipherData } from "../../../../background/abstractions/overlay.background";
import { buildSvgDomElement } from "../../../../utils"; import { buildSvgDomElement } from "../../../../utils";
import { globeIcon, lockIcon, plusIcon, viewCipherIcon } from "../../../../utils/svg-icons"; import { globeIcon, lockIcon, plusIcon, viewCipherIcon } from "../../../../utils/svg-icons";
import { import {
@@ -16,7 +16,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
private inlineMenuListContainer: HTMLDivElement; private inlineMenuListContainer: HTMLDivElement;
private resizeObserver: ResizeObserver; private resizeObserver: ResizeObserver;
private eventHandlersMemo: { [key: string]: EventListener } = {}; private eventHandlersMemo: { [key: string]: EventListener } = {};
private ciphers: OverlayCipherData[] = []; private ciphers: InlineMenuCipherData[] = [];
private ciphersList: HTMLUListElement; private ciphersList: HTMLUListElement;
private cipherListScrollIsDebounced = false; private cipherListScrollIsDebounced = false;
private cipherListScrollDebounceTimeout: number | NodeJS.Timeout; private cipherListScrollDebounceTimeout: number | NodeJS.Timeout;
@@ -122,7 +122,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param ciphers - The ciphers to display in the inline menu list. * @param ciphers - The ciphers to display in the inline menu list.
*/ */
private updateListItems(ciphers: OverlayCipherData[]) { private updateListItems(ciphers: InlineMenuCipherData[]) {
this.ciphers = ciphers; this.ciphers = ciphers;
this.currentCipherIndex = 0; this.currentCipherIndex = 0;
if (this.inlineMenuListContainer) { if (this.inlineMenuListContainer) {
@@ -231,7 +231,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the list item for. * @param cipher - The cipher to build the list item for.
*/ */
private buildInlineMenuListActionsItem(cipher: OverlayCipherData) { private buildInlineMenuListActionsItem(cipher: InlineMenuCipherData) {
const fillCipherElement = this.buildFillCipherElement(cipher); const fillCipherElement = this.buildFillCipherElement(cipher);
const viewCipherElement = this.buildViewCipherElement(cipher); const viewCipherElement = this.buildViewCipherElement(cipher);
@@ -253,7 +253,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the fill cipher button for. * @param cipher - The cipher to build the fill cipher button for.
*/ */
private buildFillCipherElement(cipher: OverlayCipherData) { private buildFillCipherElement(cipher: InlineMenuCipherData) {
const cipherIcon = this.buildCipherIconElement(cipher); const cipherIcon = this.buildCipherIconElement(cipher);
const cipherDetailsElement = this.buildCipherDetailsElement(cipher); const cipherDetailsElement = this.buildCipherDetailsElement(cipher);
@@ -281,12 +281,12 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to fill. * @param cipher - The cipher to fill.
*/ */
private handleFillCipherClickEvent = (cipher: OverlayCipherData) => { private handleFillCipherClickEvent = (cipher: InlineMenuCipherData) => {
return this.useEventHandlersMemo( return this.useEventHandlersMemo(
() => () =>
this.postMessageToParent({ this.postMessageToParent({
command: "fillSelectedAutofillInlineMenuListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: cipher.id, inlineMenuCipherId: cipher.id,
}), }),
`${cipher.id}-fill-cipher-button-click-handler`, `${cipher.id}-fill-cipher-button-click-handler`,
); );
@@ -326,7 +326,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to view. * @param cipher - The cipher to view.
*/ */
private buildViewCipherElement(cipher: OverlayCipherData) { private buildViewCipherElement(cipher: InlineMenuCipherData) {
const viewCipherElement = globalThis.document.createElement("button"); const viewCipherElement = globalThis.document.createElement("button");
viewCipherElement.tabIndex = -1; viewCipherElement.tabIndex = -1;
viewCipherElement.classList.add("view-cipher-button"); viewCipherElement.classList.add("view-cipher-button");
@@ -347,9 +347,10 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to view. * @param cipher - The cipher to view.
*/ */
private handleViewCipherClickEvent = (cipher: OverlayCipherData) => { private handleViewCipherClickEvent = (cipher: InlineMenuCipherData) => {
return this.useEventHandlersMemo( return this.useEventHandlersMemo(
() => this.postMessageToParent({ command: "viewSelectedCipher", overlayCipherId: cipher.id }), () =>
this.postMessageToParent({ command: "viewSelectedCipher", inlineMenuCipherId: cipher.id }),
`${cipher.id}-view-cipher-button-click-handler`, `${cipher.id}-view-cipher-button-click-handler`,
); );
}; };
@@ -394,7 +395,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the icon for. * @param cipher - The cipher to build the icon for.
*/ */
private buildCipherIconElement(cipher: OverlayCipherData) { private buildCipherIconElement(cipher: InlineMenuCipherData) {
const cipherIcon = globalThis.document.createElement("span"); const cipherIcon = globalThis.document.createElement("span");
cipherIcon.classList.add("cipher-icon"); cipherIcon.classList.add("cipher-icon");
cipherIcon.setAttribute("aria-hidden", "true"); cipherIcon.setAttribute("aria-hidden", "true");
@@ -432,7 +433,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the details for. * @param cipher - The cipher to build the details for.
*/ */
private buildCipherDetailsElement(cipher: OverlayCipherData) { private buildCipherDetailsElement(cipher: InlineMenuCipherData) {
const cipherNameElement = this.buildCipherNameElement(cipher); const cipherNameElement = this.buildCipherNameElement(cipher);
const cipherUserLoginElement = this.buildCipherUserLoginElement(cipher); const cipherUserLoginElement = this.buildCipherUserLoginElement(cipher);
@@ -453,7 +454,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the name element for. * @param cipher - The cipher to build the name element for.
*/ */
private buildCipherNameElement(cipher: OverlayCipherData): HTMLSpanElement | null { private buildCipherNameElement(cipher: InlineMenuCipherData): HTMLSpanElement | null {
if (!cipher.name) { if (!cipher.name) {
return null; return null;
} }
@@ -471,7 +472,7 @@ export class AutofillInlineMenuList extends AutofillInlineMenuPageElement {
* *
* @param cipher - The cipher to build the username login element for. * @param cipher - The cipher to build the username login element for.
*/ */
private buildCipherUserLoginElement(cipher: OverlayCipherData): HTMLSpanElement | null { private buildCipherUserLoginElement(cipher: InlineMenuCipherData): HTMLSpanElement | null {
if (!cipher.login?.username) { if (!cipher.login?.username) {
return null; return null;
} }

View File

@@ -7,7 +7,7 @@ import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { OverlayCipherData } from "../background/abstractions/overlay.background"; import { InlineMenuCipherData } from "../background/abstractions/overlay.background";
import AutofillField from "../models/autofill-field"; import AutofillField from "../models/autofill-field";
import AutofillForm from "../models/autofill-form"; import AutofillForm from "../models/autofill-form";
import AutofillPageDetails from "../models/autofill-page-details"; import AutofillPageDetails from "../models/autofill-page-details";
@@ -177,7 +177,10 @@ function createInitAutofillInlineMenuButtonMessageMock(
...customFields, ...customFields,
}; };
} }
function createAutofillOverlayCipherDataMock(index: number, customFields = {}): OverlayCipherData { function createAutofillOverlayCipherDataMock(
index: number,
customFields = {},
): InlineMenuCipherData {
return { return {
id: String(index), id: String(index),
name: `website login ${index}`, name: `website login ${index}`,

View File

@@ -1260,7 +1260,7 @@ export default class MainBackground {
await this.refreshBadge(); await this.refreshBadge();
await this.refreshMenu(); await this.refreshMenu();
await this.overlayBackground?.updateOverlayCiphers(); // null in popup only contexts await this.overlayBackground?.updateInlineMenuCiphers(); // null in popup only contexts
this.messagingService.send("goHome"); this.messagingService.send("goHome");
return; return;
} }
@@ -1283,7 +1283,7 @@ export default class MainBackground {
this.messagingService.send("unlocked", { userId: userId }); this.messagingService.send("unlocked", { userId: userId });
await this.refreshBadge(); await this.refreshBadge();
await this.refreshMenu(); await this.refreshMenu();
await this.overlayBackground?.updateOverlayCiphers(); // null in popup only contexts await this.overlayBackground?.updateInlineMenuCiphers(); // null in popup only contexts
await this.syncService.fullSync(false); await this.syncService.fullSync(false);
} }
} finally { } finally {