1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-13365] - don't display totp capture when in popout (#12645)

* don't display totp capture when in popout

* add canCaptureTotp method

* dry up logic

* add unit tests

* fix failing tests

* add missing mock to cipher-form story
This commit is contained in:
Jordan Aasen
2025-01-06 13:52:42 -08:00
committed by GitHub
parent 5a46991e4e
commit ddc817689a
6 changed files with 35 additions and 3 deletions

View File

@@ -2,6 +2,7 @@ import { TestBed } from "@angular/core/testing";
import qrcodeParser from "qrcode-parser";
import { BrowserApi } from "../../../platform/browser/browser-api";
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
import { BrowserTotpCaptureService } from "./browser-totp-capture.service";
@@ -13,12 +14,14 @@ describe("BrowserTotpCaptureService", () => {
let testBed: TestBed;
let service: BrowserTotpCaptureService;
let mockCaptureVisibleTab: jest.SpyInstance;
let mockBrowserPopupUtilsInPopout: jest.SpyInstance;
const validTotpUrl = "otpauth://totp/label?secret=123";
beforeEach(() => {
mockCaptureVisibleTab = jest.spyOn(BrowserApi, "captureVisibleTab");
mockCaptureVisibleTab.mockResolvedValue("screenshot");
mockBrowserPopupUtilsInPopout = jest.spyOn(BrowserPopupUtils, "inPopout");
testBed = TestBed.configureTestingModule({
providers: [BrowserTotpCaptureService],
@@ -66,4 +69,16 @@ describe("BrowserTotpCaptureService", () => {
expect(result).toBeNull();
});
describe("canCaptureTotp", () => {
it("should return true when not in a popout window", () => {
mockBrowserPopupUtilsInPopout.mockReturnValue(false);
expect(service.canCaptureTotp({} as Window)).toBe(true);
});
it("should return false when in a popout window", () => {
mockBrowserPopupUtilsInPopout.mockReturnValue(true);
expect(service.canCaptureTotp({} as Window)).toBe(false);
});
});
});

View File

@@ -4,6 +4,7 @@ import qrcodeParser from "qrcode-parser";
import { TotpCaptureService } from "@bitwarden/vault";
import { BrowserApi } from "../../../platform/browser/browser-api";
import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
/**
* Implementation of TotpCaptureService for the browser which captures the
@@ -20,4 +21,8 @@ export class BrowserTotpCaptureService implements TotpCaptureService {
}
return null;
}
canCaptureTotp(window: Window) {
return !BrowserPopupUtils.inPopout(window);
}
}

View File

@@ -6,4 +6,9 @@ export abstract class TotpCaptureService {
* Captures a TOTP secret and returns it as a string. Returns null if no TOTP secret was found.
*/
abstract captureTotpSecret(): Promise<string | null>;
/**
* Returns whether the TOTP secret can be captured from the current tab.
* Only available in the browser extension and when not in a popout window.
*/
abstract canCaptureTotp(window: Window): boolean;
}

View File

@@ -152,6 +152,7 @@ export default {
provide: TotpCaptureService,
useValue: {
captureTotpSecret: () => Promise.resolve("some-value"),
canCaptureTotp: () => true,
},
},
{

View File

@@ -434,6 +434,7 @@ describe("LoginDetailsSectionComponent", () => {
});
it("should call captureTotp when the capture totp button is clicked", fakeAsync(() => {
jest.spyOn(component, "canCaptureTotp", "get").mockReturnValue(true);
component.captureTotp = jest.fn();
fixture.detectChanges();
@@ -445,7 +446,8 @@ describe("LoginDetailsSectionComponent", () => {
}));
describe("canCaptureTotp", () => {
it("should return true when totpCaptureService is present and totp is editable", () => {
it("should return true when totpCaptureService is present and totpCaptureService.canCaptureTotp is true and totp is editable", () => {
jest.spyOn(component, "canCaptureTotp", "get").mockReturnValue(true);
component.loginDetailsForm.controls.totp.enable();
expect(component.canCaptureTotp).toBe(true);
});

View File

@@ -65,10 +65,14 @@ export class LoginDetailsSectionComponent implements OnInit {
newPasswordGenerated: boolean;
/**
* Whether the TOTP field can be captured from the current tab. Only available in the browser extension.
* Whether the TOTP field can be captured from the current tab. Only available in the browser extension and
* when not in a popout window.
*/
get canCaptureTotp() {
return this.totpCaptureService != null && this.loginDetailsForm.controls.totp.enabled;
return (
!!this.totpCaptureService?.canCaptureTotp(window) &&
this.loginDetailsForm.controls.totp.enabled
);
}
private datePipe = inject(DatePipe);