1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-20 03:13:55 +00:00

[PM-26901] Add notification handler for auto confirm (#18886)

* add notification handler for auto confirm

* add missing state check

* fix test

* isolate angular specific code from shared lib code

* clean up

* use autoconfirm method

* fix test
This commit is contained in:
Brandon Treston
2026-02-13 14:36:11 -05:00
committed by GitHub
parent 10a20a43a3
commit 2912bf05e1
25 changed files with 257 additions and 52 deletions

View File

@@ -0,0 +1,92 @@
import { TestBed } from "@angular/core/testing";
import { Router, UrlTree } from "@angular/router";
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject, firstValueFrom, Observable, of } from "rxjs";
import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm";
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { UserId } from "@bitwarden/common/types/guid";
import { ToastService } from "@bitwarden/components";
import { newGuid } from "@bitwarden/guid";
import { canAccessAutoConfirmSettings } from "./automatic-user-confirmation-settings.guard";
describe("canAccessAutoConfirmSettings", () => {
let accountService: MockProxy<AccountService>;
let autoConfirmService: MockProxy<AutomaticUserConfirmationService>;
let toastService: MockProxy<ToastService>;
let i18nService: MockProxy<I18nService>;
let router: MockProxy<Router>;
const mockUserId = newGuid() as UserId;
const mockAccount: Account = {
id: mockUserId,
email: "test@example.com",
emailVerified: true,
name: "Test User",
creationDate: undefined,
};
let activeAccount$: BehaviorSubject<Account | null>;
const runGuard = () => {
return TestBed.runInInjectionContext(() => {
return canAccessAutoConfirmSettings(null as any, null as any) as Observable<
boolean | UrlTree
>;
});
};
beforeEach(() => {
accountService = mock<AccountService>();
autoConfirmService = mock<AutomaticUserConfirmationService>();
toastService = mock<ToastService>();
i18nService = mock<I18nService>();
router = mock<Router>();
activeAccount$ = new BehaviorSubject<Account | null>(mockAccount);
accountService.activeAccount$ = activeAccount$;
TestBed.configureTestingModule({
providers: [
{ provide: AccountService, useValue: accountService },
{ provide: AutomaticUserConfirmationService, useValue: autoConfirmService },
{ provide: ToastService, useValue: toastService },
{ provide: I18nService, useValue: i18nService },
{ provide: Router, useValue: router },
],
});
});
it("should allow access when user has permission", async () => {
autoConfirmService.canManageAutoConfirm$.mockReturnValue(of(true));
const result = await firstValueFrom(runGuard());
expect(result).toBe(true);
});
it("should redirect to vault when user lacks permission", async () => {
autoConfirmService.canManageAutoConfirm$.mockReturnValue(of(false));
const mockUrlTree = {} as UrlTree;
router.createUrlTree.mockReturnValue(mockUrlTree);
const result = await firstValueFrom(runGuard());
expect(result).toBe(mockUrlTree);
expect(router.createUrlTree).toHaveBeenCalledWith(["/tabs/vault"]);
});
it("should not emit when active account is null", async () => {
activeAccount$.next(null);
autoConfirmService.canManageAutoConfirm$.mockReturnValue(of(true));
let guardEmitted = false;
const subscription = runGuard().subscribe(() => {
guardEmitted = true;
});
expect(guardEmitted).toBe(false);
subscription.unsubscribe();
});
});

View File

@@ -0,0 +1,34 @@
import { inject } from "@angular/core";
import { CanActivateFn, Router } from "@angular/router";
import { map, switchMap } from "rxjs";
import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { filterOutNullish } from "@bitwarden/common/vault/utils/observable-utilities";
import { ToastService } from "@bitwarden/components";
export const canAccessAutoConfirmSettings: CanActivateFn = () => {
const accountService = inject(AccountService);
const autoConfirmService = inject(AutomaticUserConfirmationService);
const toastService = inject(ToastService);
const i18nService = inject(I18nService);
const router = inject(Router);
return accountService.activeAccount$.pipe(
filterOutNullish(),
switchMap((user) => autoConfirmService.canManageAutoConfirm$(user.id)),
map((canManageAutoConfirm) => {
if (!canManageAutoConfirm) {
toastService.showToast({
variant: "error",
title: "",
message: i18nService.t("noPermissionsViewPage"),
});
return router.createUrlTree(["/tabs/vault"]);
}
return true;
}),
);
};

View File

@@ -0,0 +1 @@
export * from "./automatic-user-confirmation-settings.guard";