1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 09:43:23 +00:00

[PM-5189] Refactoring implementation

This commit is contained in:
Cesar Gonzalez
2024-05-03 10:49:58 -05:00
parent c178a9be08
commit 90cb44d17b
6 changed files with 92 additions and 87 deletions

View File

@@ -144,7 +144,7 @@ type InlineMenuListPortMessageHandlers = {
forceCloseAutofillInlineMenu: ({ port }: PortConnectionParam) => void; forceCloseAutofillInlineMenu: ({ port }: PortConnectionParam) => void;
autofillInlineMenuBlurred: () => void; autofillInlineMenuBlurred: () => void;
unlockVault: ({ port }: PortConnectionParam) => void; unlockVault: ({ port }: PortConnectionParam) => void;
fillSelectedListItem: ({ message, port }: PortOnMessageHandlerParams) => void; fillSelectedAutofillInlineMenuListItem: ({ message, port }: PortOnMessageHandlerParams) => void;
addNewVaultItem: ({ port }: PortConnectionParam) => void; addNewVaultItem: ({ port }: PortConnectionParam) => void;
viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void; viewSelectedCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectAutofillInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void; redirectAutofillInlineMenuFocusOut: ({ message, port }: PortOnMessageHandlerParams) => void;

View File

@@ -402,12 +402,12 @@ describe("OverlayBackground", () => {
const authStatus = AuthenticationStatus.Unlocked; const authStatus = AuthenticationStatus.Unlocked;
overlayBackground["userAuthStatus"] = AuthenticationStatus.Unlocked; overlayBackground["userAuthStatus"] = AuthenticationStatus.Unlocked;
authService.activeAccountStatus$ = new BehaviorSubject(authStatus); authService.activeAccountStatus$ = new BehaviorSubject(authStatus);
jest.spyOn(overlayBackground as any, "updateOverlayButtonAuthStatus").mockImplementation(); jest.spyOn(overlayBackground as any, "updateInlineMenuButtonAuthStatus").mockImplementation();
jest.spyOn(overlayBackground as any, "updateOverlayCiphers").mockImplementation(); jest.spyOn(overlayBackground as any, "updateOverlayCiphers").mockImplementation();
const status = await overlayBackground["getAuthStatus"](); const status = await overlayBackground["getAuthStatus"]();
expect(overlayBackground["updateOverlayButtonAuthStatus"]).not.toHaveBeenCalled(); expect(overlayBackground["updateInlineMenuButtonAuthStatus"]).not.toHaveBeenCalled();
expect(overlayBackground["updateOverlayCiphers"]).not.toHaveBeenCalled(); expect(overlayBackground["updateOverlayCiphers"]).not.toHaveBeenCalled();
expect(overlayBackground["userAuthStatus"]).toBe(authStatus); expect(overlayBackground["userAuthStatus"]).toBe(authStatus);
expect(status).toBe(authStatus); expect(status).toBe(authStatus);
@@ -417,41 +417,41 @@ describe("OverlayBackground", () => {
const authStatus = AuthenticationStatus.Unlocked; const authStatus = AuthenticationStatus.Unlocked;
overlayBackground["userAuthStatus"] = AuthenticationStatus.LoggedOut; overlayBackground["userAuthStatus"] = AuthenticationStatus.LoggedOut;
authService.activeAccountStatus$ = new BehaviorSubject(authStatus); authService.activeAccountStatus$ = new BehaviorSubject(authStatus);
jest.spyOn(overlayBackground as any, "updateOverlayButtonAuthStatus").mockImplementation(); jest.spyOn(overlayBackground as any, "updateInlineMenuButtonAuthStatus").mockImplementation();
jest.spyOn(overlayBackground as any, "updateOverlayCiphers").mockImplementation(); jest.spyOn(overlayBackground as any, "updateOverlayCiphers").mockImplementation();
await overlayBackground["getAuthStatus"](); await overlayBackground["getAuthStatus"]();
expect(overlayBackground["updateOverlayButtonAuthStatus"]).toHaveBeenCalled(); expect(overlayBackground["updateInlineMenuButtonAuthStatus"]).toHaveBeenCalled();
expect(overlayBackground["updateOverlayCiphers"]).toHaveBeenCalled(); expect(overlayBackground["updateOverlayCiphers"]).toHaveBeenCalled();
expect(overlayBackground["userAuthStatus"]).toBe(authStatus); expect(overlayBackground["userAuthStatus"]).toBe(authStatus);
}); });
}); });
describe("updateOverlayButtonAuthStatus", () => { describe("updateInlineMenuButtonAuthStatus", () => {
it("will send a message to the button port with the user's auth status", () => { it("will send a message to the button port with the user's auth status", () => {
overlayBackground["inlineMenuButtonPort"] = mock<chrome.runtime.Port>(); overlayBackground["inlineMenuButtonPort"] = mock<chrome.runtime.Port>();
jest.spyOn(overlayBackground["inlineMenuButtonPort"], "postMessage"); jest.spyOn(overlayBackground["inlineMenuButtonPort"], "postMessage");
overlayBackground["updateOverlayButtonAuthStatus"](); overlayBackground["updateInlineMenuButtonAuthStatus"]();
expect(overlayBackground["inlineMenuButtonPort"].postMessage).toHaveBeenCalledWith({ expect(overlayBackground["inlineMenuButtonPort"].postMessage).toHaveBeenCalledWith({
command: "updateOverlayButtonAuthStatus", command: "updateInlineMenuButtonAuthStatus",
authStatus: overlayBackground["userAuthStatus"], authStatus: overlayBackground["userAuthStatus"],
}); });
}); });
}); });
describe("getTranslations", () => { describe("getInlineMenuTranslations", () => {
it("will query the overlay page translations if they have not been queried", () => { it("will query the overlay page translations if they have not been queried", () => {
overlayBackground["inlineMenuPageTranslations"] = undefined; overlayBackground["inlineMenuPageTranslations"] = undefined;
jest.spyOn(overlayBackground as any, "getTranslations"); jest.spyOn(overlayBackground as any, "getInlineMenuTranslations");
jest.spyOn(overlayBackground["i18nService"], "translate").mockImplementation((key) => key); jest.spyOn(overlayBackground["i18nService"], "translate").mockImplementation((key) => key);
jest.spyOn(BrowserApi, "getUILanguage").mockReturnValue("en"); jest.spyOn(BrowserApi, "getUILanguage").mockReturnValue("en");
const translations = overlayBackground["getTranslations"](); const translations = overlayBackground["getInlineMenuTranslations"]();
expect(overlayBackground["getTranslations"]).toHaveBeenCalled(); expect(overlayBackground["getInlineMenuTranslations"]).toHaveBeenCalled();
const translationKeys = [ const translationKeys = [
"opensInANewWindow", "opensInANewWindow",
"bitwardenOverlayButton", "bitwardenOverlayButton",
@@ -540,7 +540,9 @@ describe("OverlayBackground", () => {
}; };
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } }); const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
const sendResponse = jest.fn(); const sendResponse = jest.fn();
jest.spyOn(overlayBackground as any, "getTranslations").mockReturnValue("translations"); jest
.spyOn(overlayBackground as any, "getInlineMenuTranslations")
.mockReturnValue("translations");
const returnValue = overlayBackground["handleExtensionMessage"]( const returnValue = overlayBackground["handleExtensionMessage"](
message, message,
@@ -677,7 +679,7 @@ describe("OverlayBackground", () => {
sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" }); sendMockExtensionMessage({ command: "checkAutofillInlineMenuFocused" });
expect(listPortSpy.postMessage).toHaveBeenCalledWith({ expect(listPortSpy.postMessage).toHaveBeenCalledWith({
command: "checkAutofillOverlayListFocused", command: "checkAutofillInlineMenuListFocused",
}); });
expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({ expect(buttonPortSpy.postMessage).not.toHaveBeenCalledWith({
command: "checkAutofillInlineMenuButtonFocused", command: "checkAutofillInlineMenuButtonFocused",
@@ -693,7 +695,7 @@ describe("OverlayBackground", () => {
command: "checkAutofillInlineMenuButtonFocused", command: "checkAutofillInlineMenuButtonFocused",
}); });
expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({ expect(listPortSpy.postMessage).not.toHaveBeenCalledWith({
command: "checkAutofillOverlayListFocused", command: "checkAutofillInlineMenuListFocused",
}); });
}); });
}); });
@@ -1041,7 +1043,7 @@ describe("OverlayBackground", () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(overlayBackground as any, "updateInlineMenuPosition").mockImplementation(); jest.spyOn(overlayBackground as any, "updateInlineMenuPosition").mockImplementation();
jest.spyOn(overlayBackground as any, "getAuthStatus").mockImplementation(); jest.spyOn(overlayBackground as any, "getAuthStatus").mockImplementation();
jest.spyOn(overlayBackground as any, "getTranslations").mockImplementation(); jest.spyOn(overlayBackground as any, "getInlineMenuTranslations").mockImplementation();
jest.spyOn(overlayBackground as any, "getOverlayCipherData").mockImplementation(); jest.spyOn(overlayBackground as any, "getOverlayCipherData").mockImplementation();
}); });
@@ -1067,7 +1069,7 @@ describe("OverlayBackground", () => {
expect(listPortSpy.postMessage).toHaveBeenCalled(); expect(listPortSpy.postMessage).toHaveBeenCalled();
expect(overlayBackground["getAuthStatus"]).toHaveBeenCalled(); expect(overlayBackground["getAuthStatus"]).toHaveBeenCalled();
expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/list.css"); expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/list.css");
expect(overlayBackground["getTranslations"]).toHaveBeenCalled(); expect(overlayBackground["getInlineMenuTranslations"]).toHaveBeenCalled();
expect(overlayBackground["getOverlayCipherData"]).toHaveBeenCalled(); expect(overlayBackground["getOverlayCipherData"]).toHaveBeenCalled();
expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith( expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith(
{ overlayElement: AutofillOverlayElement.List }, { overlayElement: AutofillOverlayElement.List },
@@ -1088,7 +1090,7 @@ describe("OverlayBackground", () => {
expect(buttonPortSpy.postMessage).toHaveBeenCalled(); expect(buttonPortSpy.postMessage).toHaveBeenCalled();
expect(overlayBackground["getAuthStatus"]).toHaveBeenCalled(); expect(overlayBackground["getAuthStatus"]).toHaveBeenCalled();
expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/button.css"); expect(chrome.runtime.getURL).toHaveBeenCalledWith("overlay/button.css");
expect(overlayBackground["getTranslations"]).toHaveBeenCalled(); expect(overlayBackground["getInlineMenuTranslations"]).toHaveBeenCalled();
expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith( expect(overlayBackground["updateInlineMenuPosition"]).toHaveBeenCalledWith(
{ overlayElement: AutofillOverlayElement.Button }, { overlayElement: AutofillOverlayElement.Button },
buttonPortSpy.sender, buttonPortSpy.sender,
@@ -1318,7 +1320,7 @@ describe("OverlayBackground", () => {
}); });
}); });
describe("fillSelectedListItem", () => { describe("fillSelectedAutofillInlineMenuListItem", () => {
let getLoginCiphersSpy: jest.SpyInstance; let getLoginCiphersSpy: jest.SpyInstance;
let isPasswordRepromptRequiredSpy: jest.SpyInstance; let isPasswordRepromptRequiredSpy: jest.SpyInstance;
let doAutoFillSpy: jest.SpyInstance; let doAutoFillSpy: jest.SpyInstance;
@@ -1339,7 +1341,7 @@ describe("OverlayBackground", () => {
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 () => {
sendPortMessage(listMessageConnectorPortSpy, { sendPortMessage(listMessageConnectorPortSpy, {
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
portKey, portKey,
}); });
await flushPromises(); await flushPromises();
@@ -1351,7 +1353,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(listMessageConnectorPortSpy, { sendPortMessage(listMessageConnectorPortSpy, {
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-1", overlayCipherId: "overlay-cipher-1",
portKey, portKey,
}); });
@@ -1375,7 +1377,7 @@ describe("OverlayBackground", () => {
isPasswordRepromptRequiredSpy.mockResolvedValue(true); isPasswordRepromptRequiredSpy.mockResolvedValue(true);
sendPortMessage(listMessageConnectorPortSpy, { sendPortMessage(listMessageConnectorPortSpy, {
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-1", overlayCipherId: "overlay-cipher-1",
portKey, portKey,
}); });
@@ -1409,7 +1411,7 @@ describe("OverlayBackground", () => {
isPasswordRepromptRequiredSpy.mockResolvedValue(false); isPasswordRepromptRequiredSpy.mockResolvedValue(false);
sendPortMessage(listMessageConnectorPortSpy, { sendPortMessage(listMessageConnectorPortSpy, {
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-2", overlayCipherId: "overlay-cipher-2",
portKey, portKey,
}); });
@@ -1448,7 +1450,7 @@ describe("OverlayBackground", () => {
doAutoFillSpy.mockReturnValueOnce("totp-code"); doAutoFillSpy.mockReturnValueOnce("totp-code");
sendPortMessage(listMessageConnectorPortSpy, { sendPortMessage(listMessageConnectorPortSpy, {
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: "overlay-cipher-2", overlayCipherId: "overlay-cipher-2",
portKey, portKey,
}); });
@@ -1533,7 +1535,7 @@ describe("OverlayBackground", () => {
}; };
const redirectOverlayFocusOutSpy = jest.spyOn( const redirectOverlayFocusOutSpy = jest.spyOn(
overlayBackground as any, overlayBackground as any,
"redirectAutofillInlineMenuFocusOut", "redirectInlineMenuFocusOut",
); );
sendPortMessage(listMessageConnectorPortSpy, message); sendPortMessage(listMessageConnectorPortSpy, message);

View File

@@ -109,7 +109,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.closeInlineMenu(port.sender, { forceCloseAutofillInlineMenu: true }), this.closeInlineMenu(port.sender, { forceCloseAutofillInlineMenu: true }),
autofillInlineMenuBlurred: () => this.checkInlineMenuButtonFocused(), autofillInlineMenuBlurred: () => this.checkInlineMenuButtonFocused(),
unlockVault: ({ port }) => this.unlockVault(port), unlockVault: ({ port }) => this.unlockVault(port),
fillSelectedListItem: ({ message, port }) => this.fillSelectedOverlayListItem(message, port), fillSelectedAutofillInlineMenuListItem: ({ message, port }) =>
this.fillSelectedInlineMenuListItem(message, port),
addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port), addNewVaultItem: ({ port }) => this.getNewVaultItemDetails(port),
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port), viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
redirectAutofillInlineMenuFocusOut: ({ message, port }) => redirectAutofillInlineMenuFocusOut: ({ message, port }) =>
@@ -166,7 +167,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Updates the overlay list's ciphers and sends the updated list to the overlay list iframe. * Updates the inline menu list's ciphers and sends the updated list to the inline menu list iframe.
* 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.
*/ */
@@ -194,7 +195,7 @@ 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 overlay list. * objects that contain the cipher data needed for the inline menu list.
*/ */
private async getOverlayCipherData(): Promise<OverlayCipherData[]> { private async getOverlayCipherData(): Promise<OverlayCipherData[]> {
const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$); const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$);
@@ -347,13 +348,13 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Triggers autofill for the selected cipher in the overlay 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 overlayLoginCiphers map. Does not correspond to the actual cipher's ID. * @param overlayCipherId - Cipher ID corresponding to the overlayLoginCiphers 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 fillSelectedOverlayListItem( private async fillSelectedInlineMenuListItem(
{ overlayCipherId }: OverlayPortMessage, { overlayCipherId }: OverlayPortMessage,
{ sender }: chrome.runtime.Port, { sender }: chrome.runtime.Port,
) { ) {
@@ -383,8 +384,8 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Checks if the overlay is focused. Will check the overlay list * Checks if the inline menu is focused. Will check the inline menu list
* if it is open, otherwise it will check the overlay button. * if it is open, otherwise it will check the inline menu button.
*/ */
private checkInlineMenuFocused() { private checkInlineMenuFocused() {
if (this.inlineMenuListPort) { if (this.inlineMenuListPort) {
@@ -397,24 +398,24 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Posts a message to the overlay button iframe to check if it is focused. * Posts a message to the inline menu button iframe to check if it is focused.
*/ */
private checkInlineMenuButtonFocused() { private checkInlineMenuButtonFocused() {
this.inlineMenuButtonPort?.postMessage({ command: "checkAutofillInlineMenuButtonFocused" }); this.inlineMenuButtonPort?.postMessage({ command: "checkAutofillInlineMenuButtonFocused" });
} }
/** /**
* Posts a message to the overlay list iframe to check if it is focused. * Posts a message to the inline menu list iframe to check if it is focused.
*/ */
private checkInlineMenuListFocused() { private checkInlineMenuListFocused() {
this.inlineMenuListPort?.postMessage({ command: "checkAutofillOverlayListFocused" }); this.inlineMenuListPort?.postMessage({ command: "checkAutofillInlineMenuListFocused" });
} }
/** /**
* Sends a message to the sender tab to close the autofill overlay. * Sends a message to the sender tab to close the autofill inline menu.
* *
* @param sender - The sender of the port message * @param sender - The sender of the port message
* @param forceCloseAutofillInlineMenu - Identifies whether the overlay should be forced closed * @param forceCloseAutofillInlineMenu - Identifies whether the inline menu should be forced closed
* @param overlayElement - The overlay element to close, either the list or button * @param overlayElement - The overlay element to close, either the list or button
*/ */
private closeInlineMenu( private closeInlineMenu(
@@ -475,7 +476,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Updates the position of either the overlay list or button. The position * Updates the position of either the inline menu list or button. The position
* is based on the focused field's position and dimensions. * is based on the focused field's position and dimensions.
* *
* @param overlayElement - The overlay element to update, either the list or button * @param overlayElement - The overlay element to update, either the list or button
@@ -504,7 +505,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
if (overlayElement === AutofillOverlayElement.Button) { if (overlayElement === AutofillOverlayElement.Button) {
this.inlineMenuButtonPort?.postMessage({ this.inlineMenuButtonPort?.postMessage({
command: "updateIframePosition", command: "updateIframePosition",
styles: this.getOverlayButtonPosition(subFrameOffsets), styles: this.getInlineMenuButtonPosition(subFrameOffsets),
}); });
return; return;
@@ -512,15 +513,15 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.inlineMenuListPort?.postMessage({ this.inlineMenuListPort?.postMessage({
command: "updateIframePosition", command: "updateIframePosition",
styles: this.getOverlayListPosition(subFrameOffsets), styles: this.getInlineMenuListPosition(subFrameOffsets),
}); });
} }
/** /**
* Gets the position of the focused field and calculates the position * Gets the position of the focused field and calculates the position
* of the overlay button based on the focused field's position and dimensions. * of the inline menu button based on the focused field's position and dimensions.
*/ */
private getOverlayButtonPosition(subFrameOffsets: SubFrameOffsetData) { private getInlineMenuButtonPosition(subFrameOffsets: SubFrameOffsetData) {
if (!this.focusedFieldData) { if (!this.focusedFieldData) {
return; return;
} }
@@ -555,9 +556,9 @@ class OverlayBackground implements OverlayBackgroundInterface {
/** /**
* Gets the position of the focused field and calculates the position * Gets the position of the focused field and calculates the position
* of the overlay list based on the focused field's position and dimensions. * of the inline menu list based on the focused field's position and dimensions.
*/ */
private getOverlayListPosition(subFrameOffsets: SubFrameOffsetData) { private getInlineMenuListPosition(subFrameOffsets: SubFrameOffsetData) {
if (!this.focusedFieldData) { if (!this.focusedFieldData) {
return; return;
} }
@@ -587,9 +588,9 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Updates the overlay's visibility based on the display property passed in the extension message. * Updates the inline menu's visibility based on the display property passed in the extension message.
* *
* @param display - The display property of the overlay, either "block" or "none" * @param display - The display property of the inline menu, either "block" or "none"
* @param sender - The sender of the extension message * @param sender - The sender of the extension message
*/ */
private updateInlineMenuHidden( private updateInlineMenuHidden(
@@ -617,10 +618,10 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Sends a message to the currently active tab to open the autofill overlay. * Sends a message to the currently active tab to open the autofill inline menu.
* *
* @param isFocusingFieldElement - Identifies whether the field element should be focused when the overlay is opened * @param isFocusingFieldElement - Identifies whether the field element should be focused when the inline menu is opened
* @param isOpeningFullAutofillInlineMenu - Identifies whether the full overlay should be forced open regardless of other states * @param isOpeningFullAutofillInlineMenu - Identifies whether the full inline menu should be forced open regardless of other states
*/ */
private async openInlineMenu( private async openInlineMenu(
isFocusingFieldElement = false, isFocusingFieldElement = false,
@@ -643,16 +644,16 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Gets the overlay's visibility setting from the settings service. * Gets the inline menu's visibility setting from the settings service.
*/ */
private async getInlineMenuVisibility(): Promise<InlineMenuVisibilitySetting> { private async getInlineMenuVisibility(): Promise<InlineMenuVisibilitySetting> {
return await firstValueFrom(this.autofillSettingsService.inlineMenuVisibility$); return await firstValueFrom(this.autofillSettingsService.inlineMenuVisibility$);
} }
/** /**
* Gets the user's authentication status from the auth service. If the user's * Gets the user's authentication status from the auth service. If the user's authentication
* authentication status has changed, the overlay button's authentication status * status has changed, the inline menu button's authentication status will be updated
* will be updated and the overlay list's ciphers will be updated. * and the inline menu list's ciphers will be updated.
*/ */
private async getAuthStatus() { private async getAuthStatus() {
const formerAuthStatus = this.userAuthStatus; const formerAuthStatus = this.userAuthStatus;
@@ -662,7 +663,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
this.userAuthStatus !== formerAuthStatus && this.userAuthStatus !== formerAuthStatus &&
this.userAuthStatus === AuthenticationStatus.Unlocked this.userAuthStatus === AuthenticationStatus.Unlocked
) { ) {
this.updateOverlayButtonAuthStatus(); this.updateInlineMenuButtonAuthStatus();
await this.updateOverlayCiphers(); await this.updateOverlayCiphers();
} }
@@ -670,21 +671,21 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Sends a message to the overlay button to update its authentication status. * Sends a message to the inline menu button to update its authentication status.
*/ */
private updateOverlayButtonAuthStatus() { private updateInlineMenuButtonAuthStatus() {
this.inlineMenuButtonPort?.postMessage({ this.inlineMenuButtonPort?.postMessage({
command: "updateOverlayButtonAuthStatus", command: "updateInlineMenuButtonAuthStatus",
authStatus: this.userAuthStatus, authStatus: this.userAuthStatus,
}); });
} }
/** /**
* Handles the overlay button being clicked. If the user is not authenticated, * Handles the inline menu button being clicked. If the user is not authenticated,
* the vault will be unlocked. If the user is authenticated, the overlay will * the vault will be unlocked. If the user is authenticated, the inline menu will
* be opened. * be opened.
* *
* @param port - The port of the overlay button * @param port - The port of the inline menu button
*/ */
private handleInlineMenuButtonClicked(port: chrome.runtime.Port) { private handleInlineMenuButtonClicked(port: chrome.runtime.Port) {
if (this.userAuthStatus !== AuthenticationStatus.Unlocked) { if (this.userAuthStatus !== AuthenticationStatus.Unlocked) {
@@ -698,7 +699,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
/** /**
* Facilitates opening the unlock popout window. * Facilitates opening the unlock popout window.
* *
* @param port - The port of the overlay list * @param port - The port of the inline menu list
*/ */
private async unlockVault(port: chrome.runtime.Port) { private async unlockVault(port: chrome.runtime.Port) {
const { sender } = port; const { sender } = port;
@@ -738,14 +739,14 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Facilitates redirecting focus to the overlay list. * Facilitates redirecting focus to the inline menu list.
*/ */
private focusInlineMenuList() { private focusInlineMenuList() {
this.inlineMenuListPort?.postMessage({ command: "focusInlineMenuList" }); this.inlineMenuListPort?.postMessage({ command: "focusInlineMenuList" });
} }
/** /**
* Updates the authentication status for the user and opens the overlay if * Updates the authentication status for the user and opens the inline menu if
* a followup command is present in the message. * a followup command is present in the message.
* *
* @param message - Extension message received from the `unlockCompleted` command * @param message - Extension message received from the `unlockCompleted` command
@@ -759,9 +760,9 @@ class OverlayBackground implements OverlayBackgroundInterface {
} }
/** /**
* Gets the translations for the overlay page. * Gets the translations for the inline menu page.
*/ */
private getTranslations() { private getInlineMenuTranslations() {
if (!this.inlineMenuPageTranslations) { if (!this.inlineMenuPageTranslations) {
this.inlineMenuPageTranslations = { this.inlineMenuPageTranslations = {
locale: BrowserApi.getUILanguage(), locale: BrowserApi.getUILanguage(),
@@ -785,7 +786,7 @@ class OverlayBackground implements OverlayBackgroundInterface {
/** /**
* Facilitates redirecting focus out of one of the * Facilitates redirecting focus out of one of the
* overlay elements to elements on the page. * inline menu elements to elements on the page.
* *
* @param direction - The direction to redirect focus to (either "next", "previous" or "current) * @param direction - The direction to redirect focus to (either "next", "previous" or "current)
* @param sender - The sender of the port message * @param sender - The sender of the port message
@@ -952,21 +953,21 @@ class OverlayBackground implements OverlayBackgroundInterface {
* @param port - The port that connected to the extension background * @param port - The port that connected to the extension background
*/ */
private handlePortOnConnect = async (port: chrome.runtime.Port) => { private handlePortOnConnect = async (port: chrome.runtime.Port) => {
const isOverlayListMessageConnector = port.name === AutofillOverlayPort.ListMessageConnector; const isInlineMenuListMessageConnector = port.name === AutofillOverlayPort.ListMessageConnector;
const isOverlayButtonMessageConnector = const isInlineMenuButtonMessageConnector =
port.name === AutofillOverlayPort.ButtonMessageConnector; port.name === AutofillOverlayPort.ButtonMessageConnector;
if (isOverlayListMessageConnector || isOverlayButtonMessageConnector) { if (isInlineMenuListMessageConnector || isInlineMenuButtonMessageConnector) {
port.onMessage.addListener(this.handleOverlayElementPortMessage); port.onMessage.addListener(this.handleOverlayElementPortMessage);
return; return;
} }
const isOverlayListPort = port.name === AutofillOverlayPort.List; const isInlineMenuListPort = port.name === AutofillOverlayPort.List;
const isOverlayButtonPort = port.name === AutofillOverlayPort.Button; const isInlineMenuButtonPort = port.name === AutofillOverlayPort.Button;
if (!isOverlayListPort && !isOverlayButtonPort) { if (!isInlineMenuListPort && !isInlineMenuButtonPort) {
return; return;
} }
if (isOverlayListPort) { if (isInlineMenuListPort) {
this.inlineMenuListPort = port; this.inlineMenuListPort = port;
} else { } else {
this.inlineMenuButtonPort = port; this.inlineMenuButtonPort = port;
@@ -974,24 +975,26 @@ class OverlayBackground implements OverlayBackgroundInterface {
port.onDisconnect.addListener(this.handlePortOnDisconnect); port.onDisconnect.addListener(this.handlePortOnDisconnect);
port.postMessage({ port.postMessage({
command: `initAutofillOverlay${isOverlayListPort ? "List" : "Button"}`, command: `initAutofillOverlay${isInlineMenuListPort ? "List" : "Button"}`,
iframeUrl: chrome.runtime.getURL(`overlay/${isOverlayListPort ? "list" : "button"}.html`), iframeUrl: chrome.runtime.getURL(`overlay/${isInlineMenuListPort ? "list" : "button"}.html`),
pageTitle: chrome.i18n.getMessage( pageTitle: chrome.i18n.getMessage(
isOverlayListPort ? "bitwardenVault" : "bitwardenOverlayButton", isInlineMenuListPort ? "bitwardenVault" : "bitwardenOverlayButton",
), ),
authStatus: await this.getAuthStatus(), authStatus: await this.getAuthStatus(),
styleSheetUrl: chrome.runtime.getURL(`overlay/${isOverlayListPort ? "list" : "button"}.css`), styleSheetUrl: chrome.runtime.getURL(
`overlay/${isInlineMenuListPort ? "list" : "button"}.css`,
),
theme: await firstValueFrom(this.themeStateService.selectedTheme$), theme: await firstValueFrom(this.themeStateService.selectedTheme$),
translations: this.getTranslations(), translations: this.getInlineMenuTranslations(),
ciphers: isOverlayListPort ? await this.getOverlayCipherData() : null, ciphers: isInlineMenuListPort ? await this.getOverlayCipherData() : null,
portKey: this.portKeyForTab[port.sender.tab.id], portKey: this.portKeyForTab[port.sender.tab.id],
portName: isOverlayListPort portName: isInlineMenuListPort
? AutofillOverlayPort.ListMessageConnector ? AutofillOverlayPort.ListMessageConnector
: AutofillOverlayPort.ButtonMessageConnector, : AutofillOverlayPort.ButtonMessageConnector,
}); });
void this.updateInlineMenuPosition( void this.updateInlineMenuPosition(
{ {
overlayElement: isOverlayListPort overlayElement: isInlineMenuListPort
? AutofillOverlayElement.List ? AutofillOverlayElement.List
: AutofillOverlayElement.Button, : AutofillOverlayElement.Button,
}, },

View File

@@ -20,7 +20,7 @@ type InitAutofillOverlayListMessage = OverlayListMessage & {
type OverlayListWindowMessageHandlers = { type OverlayListWindowMessageHandlers = {
[key: string]: CallableFunction; [key: string]: CallableFunction;
initAutofillOverlayList: ({ message }: { message: InitAutofillOverlayListMessage }) => void; initAutofillOverlayList: ({ message }: { message: InitAutofillOverlayListMessage }) => void;
checkAutofillOverlayListFocused: () => void; checkAutofillInlineMenuListFocused: () => void;
updateOverlayListCiphers: ({ message }: { message: UpdateOverlayListCiphersMessage }) => void; updateOverlayListCiphers: ({ message }: { message: UpdateOverlayListCiphersMessage }) => void;
focusInlineMenuList: () => void; focusInlineMenuList: () => void;
}; };

View File

@@ -140,7 +140,7 @@ describe("AutofillOverlayList", () => {
fillCipherButton.dispatchEvent(new Event("click")); fillCipherButton.dispatchEvent(new Event("click"));
expect(globalThis.parent.postMessage).toHaveBeenCalledWith( expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "fillSelectedListItem", overlayCipherId: "1", portKey }, { command: "fillSelectedAutofillInlineMenuListItem", overlayCipherId: "1", portKey },
"*", "*",
); );
}); });
@@ -292,7 +292,7 @@ describe("AutofillOverlayList", () => {
it("does not post a `checkAutofillInlineMenuButtonFocused` message to the parent if the overlay is currently focused", () => { it("does not post a `checkAutofillInlineMenuButtonFocused` message to the parent if the overlay is currently focused", () => {
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(true); jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(true);
postWindowMessage({ command: "checkAutofillOverlayListFocused" }); postWindowMessage({ command: "checkAutofillInlineMenuListFocused" });
expect(globalThis.parent.postMessage).not.toHaveBeenCalled(); expect(globalThis.parent.postMessage).not.toHaveBeenCalled();
}); });
@@ -300,7 +300,7 @@ describe("AutofillOverlayList", () => {
it("posts a `checkAutofillInlineMenuButtonFocused` message to the parent if the overlay is not currently focused", () => { it("posts a `checkAutofillInlineMenuButtonFocused` message to the parent if the overlay is not currently focused", () => {
jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(false); jest.spyOn(globalThis.document, "hasFocus").mockReturnValue(false);
postWindowMessage({ command: "checkAutofillOverlayListFocused" }); postWindowMessage({ command: "checkAutofillInlineMenuListFocused" });
expect(globalThis.parent.postMessage).toHaveBeenCalledWith( expect(globalThis.parent.postMessage).toHaveBeenCalledWith(
{ command: "checkAutofillInlineMenuButtonFocused", portKey }, { command: "checkAutofillInlineMenuButtonFocused", portKey },

View File

@@ -24,7 +24,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
private readonly showCiphersPerPage = 6; private readonly showCiphersPerPage = 6;
private readonly overlayListWindowMessageHandlers: OverlayListWindowMessageHandlers = { private readonly overlayListWindowMessageHandlers: OverlayListWindowMessageHandlers = {
initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message), initAutofillOverlayList: ({ message }) => this.initAutofillOverlayList(message),
checkAutofillOverlayListFocused: () => this.checkInlineMenuListFocused(), checkAutofillInlineMenuListFocused: () => this.checkInlineMenuListFocused(),
updateOverlayListCiphers: ({ message }) => this.updateListItems(message.ciphers), updateOverlayListCiphers: ({ message }) => this.updateListItems(message.ciphers),
focusInlineMenuList: () => this.focusInlineMenuList(), focusInlineMenuList: () => this.focusInlineMenuList(),
}; };
@@ -279,7 +279,7 @@ class AutofillOverlayList extends AutofillOverlayPageElement {
return this.useEventHandlersMemo( return this.useEventHandlersMemo(
() => () =>
this.postMessageToParent({ this.postMessageToParent({
command: "fillSelectedListItem", command: "fillSelectedAutofillInlineMenuListItem",
overlayCipherId: cipher.id, overlayCipherId: cipher.id,
}), }),
`${cipher.id}-fill-cipher-button-click-handler`, `${cipher.id}-fill-cipher-button-click-handler`,