mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 11:43:51 +00:00
* Passed in userId on RemovePasswordComponent. * Added userId on other references to KeyConnectorService methods * remove password component refactor, test coverage, enabled strict * explicit user id provided to key connector service * redirect to / instead when user not logged in or not managing organization * key connector service explicit user id * key connector service no longer requires account service * key connector service missing null type * cli convert to key connector unit tests * remove unnecessary SyncService * error toast not showing on ErrorResponse * bad import due to merge conflict * bad import due to merge conflict * missing loading in remove password component for browser extension * error handling in remove password component * organization observable race condition in key-connector * usesKeyConnector always returns boolean * unit test coverage * key connector reactive * reactive key connector service * introducing convertAccountRequired$ * cli build fix * moving message sending side effect to sync * key connector service unit tests * fix unit tests * move key connector components to KM team ownership * new unit tests in wrong place * key connector domain shown in remove password component * type safety improvements * convert to key connector command localization * key connector domain in convert to key connector command * convert to key connector command unit tests with prompt assert * organization name placement change in the remove password component * unit test update * show key connector domain for new sso users * confirm key connector domain page does not require auth guard * confirm key connector domain page showing correctly * key connector url required to be provided when migrating user * missing locales * desktop styling * have to sync and navigate to vault after key connector keys exchange * logging verbosity * splitting the web client * splitting the browser client * cleanup * splitting the desktop client * cleanup * cleanup * not necessary if condition * key connector domain tests fix for sso componrnt and login strategy * confirm key connector domain base component unit tests coverage * confirm key connector domain command for cli * confirm key connector domain command for cli unit tests * design adjustments removed repeated text, vertical buttons on desktop, wrong paddings on browser extension * key connector service unit test coverage * new linting rules fixes * accept invitation to organization called twice results in error. Web vault remembers it's original route destination, which we do not want in case of accepting invitation and Key Connector, since provisioning new user through SSO and Key Connector, the user is already accepted. * moved required key connector domain confirmation into state * revert redirect from auth guard * cleanup * sso-login.strategy unit test failing * two-factor-auth.component unit test failing * two-factor-auth.component unit test coverage * cli unit test failing * removal of redundant logs * removal of un-necessary new lines * consolidated component * consolidated component css cleanup * use KdfConfig type * consolidate KDF into KdfConfig type in identity token response * moving KC requiresDomainConfirmation lower in order, after successful auth * simplification of trySetUserKeyWithMasterKey * redirect to confirm key connector route when locked but can't unlock yet --------- Co-authored-by: Todd Martin <tmartin@bitwarden.com>
222 lines
8.3 KiB
TypeScript
222 lines
8.3 KiB
TypeScript
import { TestBed } from "@angular/core/testing";
|
|
import { Router } from "@angular/router";
|
|
import { RouterTestingModule } from "@angular/router/testing";
|
|
import { MockProxy, mock } from "jest-mock-extended";
|
|
import { BehaviorSubject, of } from "rxjs";
|
|
|
|
import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec";
|
|
import {
|
|
Account,
|
|
AccountInfo,
|
|
AccountService,
|
|
} from "@bitwarden/common/auth/abstractions/account.service";
|
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
|
import { ClientType } from "@bitwarden/common/enums";
|
|
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction";
|
|
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
|
|
import { KeyConnectorDomainConfirmation } from "@bitwarden/common/key-management/key-connector/models/key-connector-domain-confirmation";
|
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout";
|
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
import { UserId } from "@bitwarden/common/types/guid";
|
|
import { KeyService } from "@bitwarden/key-management";
|
|
|
|
import { lockGuard } from "./lock.guard";
|
|
|
|
interface SetupParams {
|
|
authStatus: AuthenticationStatus;
|
|
canLock?: boolean;
|
|
clientType?: ClientType;
|
|
everHadUserKey?: boolean;
|
|
supportsDeviceTrust?: boolean;
|
|
hasMasterPassword?: boolean;
|
|
}
|
|
|
|
describe("lockGuard", () => {
|
|
const keyConnectorService = mock<KeyConnectorService>();
|
|
|
|
const setup = (setupParams: SetupParams) => {
|
|
const authService: MockProxy<AuthService> = mock<AuthService>();
|
|
authService.authStatusFor$.mockReturnValue(of(setupParams.authStatus));
|
|
|
|
const vaultTimeoutSettingsService: MockProxy<VaultTimeoutSettingsService> =
|
|
mock<VaultTimeoutSettingsService>();
|
|
vaultTimeoutSettingsService.canLock.mockResolvedValue(setupParams.canLock ?? true);
|
|
|
|
const keyService: MockProxy<KeyService> = mock<KeyService>();
|
|
keyService.everHadUserKey$.mockReturnValue(of(setupParams.everHadUserKey ?? true));
|
|
|
|
const platformUtilService: MockProxy<PlatformUtilsService> = mock<PlatformUtilsService>();
|
|
platformUtilService.getClientType.mockReturnValue(setupParams.clientType ?? ClientType.Web);
|
|
|
|
const messagingService: MockProxy<MessagingService> = mock<MessagingService>();
|
|
|
|
const deviceTrustService: MockProxy<DeviceTrustServiceAbstraction> =
|
|
mock<DeviceTrustServiceAbstraction>();
|
|
deviceTrustService.supportsDeviceTrust$ = of(setupParams.supportsDeviceTrust ?? false);
|
|
|
|
const userVerificationService: MockProxy<UserVerificationService> =
|
|
mock<UserVerificationService>();
|
|
userVerificationService.hasMasterPassword.mockResolvedValue(
|
|
setupParams.hasMasterPassword ?? true,
|
|
);
|
|
|
|
keyConnectorService.requiresDomainConfirmation$.mockReturnValue(of(null));
|
|
|
|
const accountService: MockProxy<AccountService> = mock<AccountService>();
|
|
const activeAccountSubject = new BehaviorSubject<Account | null>(null);
|
|
accountService.activeAccount$ = activeAccountSubject;
|
|
activeAccountSubject.next(
|
|
Object.assign(
|
|
{
|
|
name: "Test User 1",
|
|
email: "test@email.com",
|
|
emailVerified: true,
|
|
} as AccountInfo,
|
|
{ id: "test-id" as UserId },
|
|
),
|
|
);
|
|
|
|
const testBed = TestBed.configureTestingModule({
|
|
imports: [
|
|
RouterTestingModule.withRoutes([
|
|
{ path: "", component: EmptyComponent },
|
|
{ path: "lock", component: EmptyComponent, canActivate: [lockGuard()] },
|
|
{ path: "non-lock-route", component: EmptyComponent },
|
|
{ path: "confirm-key-connector-domain", component: EmptyComponent },
|
|
]),
|
|
],
|
|
providers: [
|
|
{ provide: AuthService, useValue: authService },
|
|
{ provide: MessagingService, useValue: messagingService },
|
|
{ provide: AccountService, useValue: accountService },
|
|
{ provide: VaultTimeoutSettingsService, useValue: vaultTimeoutSettingsService },
|
|
{ provide: KeyService, useValue: keyService },
|
|
{ provide: PlatformUtilsService, useValue: platformUtilService },
|
|
{ provide: DeviceTrustServiceAbstraction, useValue: deviceTrustService },
|
|
{ provide: UserVerificationService, useValue: userVerificationService },
|
|
{ provide: KeyConnectorService, useValue: keyConnectorService },
|
|
],
|
|
});
|
|
|
|
return {
|
|
router: testBed.inject(Router),
|
|
messagingService,
|
|
};
|
|
};
|
|
|
|
it("should be created", () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
});
|
|
expect(router).toBeTruthy();
|
|
});
|
|
|
|
it("should redirect to the root route when the user is Unlocked", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Unlocked,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/");
|
|
});
|
|
|
|
it("should redirect to the root route when the user is LoggedOut", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.LoggedOut,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/");
|
|
});
|
|
|
|
it("should allow navigation to the lock route when the user is Locked and they can lock", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: true,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/lock");
|
|
});
|
|
|
|
it("should allow navigation to the lock route when the user is locked, they can lock, and device trust is not supported", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: true,
|
|
supportsDeviceTrust: false,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/lock");
|
|
});
|
|
|
|
it("should not allow navigation to the lock route when canLock is false", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: false,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/");
|
|
});
|
|
|
|
it("should allow navigation to the lock route when device trust is supported, the user has a MP, and the user is coming from the login-initiated page", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: true,
|
|
clientType: ClientType.Web,
|
|
everHadUserKey: false,
|
|
supportsDeviceTrust: true,
|
|
hasMasterPassword: true,
|
|
});
|
|
|
|
await router.navigate(["lock"], { queryParams: { from: "login-initiated" } });
|
|
expect(router.url).toBe("/lock?from=login-initiated");
|
|
});
|
|
|
|
it("should allow navigation to the lock route when TDE is disabled, the user doesn't have a MP, and the user has had a user key", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: true,
|
|
supportsDeviceTrust: false,
|
|
hasMasterPassword: false,
|
|
everHadUserKey: true,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/lock");
|
|
});
|
|
|
|
it("should not allow navigation to the lock route when device trust is supported and the user has not ever had a user key", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: true,
|
|
clientType: ClientType.Web,
|
|
everHadUserKey: false,
|
|
supportsDeviceTrust: true,
|
|
hasMasterPassword: false,
|
|
});
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/");
|
|
});
|
|
|
|
it("should redirect to the confirm-key-connector-domain route when the auth status is locked, can't lock and requires key connector domain confirmation", async () => {
|
|
const { router } = setup({
|
|
authStatus: AuthenticationStatus.Locked,
|
|
canLock: false,
|
|
});
|
|
keyConnectorService.requiresDomainConfirmation$.mockReturnValue(
|
|
of({
|
|
keyConnectorUrl: "https://example.com",
|
|
} as KeyConnectorDomainConfirmation),
|
|
);
|
|
|
|
await router.navigate(["lock"]);
|
|
expect(router.url).toBe("/confirm-key-connector-domain");
|
|
});
|
|
});
|