1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 07:43:35 +00:00
Files
browser/libs/angular/src/auth/guards/lock.guard.ts
Jared Snider 0d829b7398 Auth/PM-3515 - Lock component Tech Debt Clean up (#10332)
* PM-3515 - Lock component - remove isUnlocked check on lock comp load b/c lock guard should cover all cases with its existing logic for all clients.

* PM-3515 - VaultTimeoutSettingsSvc - Add new canLock method

* PM-3515 - Refactor logic out of lock component that belongs in lock guard. Update lock guard to reject route activation if a user can't lock whereas we used to log the user out when they landed on the lock comp.

* PM-3515 - WIP on testing all lock guard scenarios

* PM-3515 - Refactor lock guard tests + add more tests

* PM-3515 - LockGuard - if TDE user that is authN directly navigates from login-init to lock for whatever reason (only possible on web with url bar), reject that navigation directly instead of throwing them up to the redirect guard

* PM-3515 - More LockGuard tests

* PM-3515 - Update comment
2024-08-12 15:51:57 -04:00

89 lines
3.7 KiB
TypeScript

import { inject } from "@angular/core";
import {
ActivatedRouteSnapshot,
CanActivateFn,
Router,
RouterStateSnapshot,
} from "@angular/router";
import { firstValueFrom } from "rxjs";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
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 { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
/**
* Only allow access to this route if the vault is locked.
* If TDE is enabled then the user must also have had a user key at some point.
* Otherwise reject navigation.
*
* TODO: This should return Observable<boolean | UrlTree> once we can remove all the promises
*/
export function lockGuard(): CanActivateFn {
return async (
activatedRouteSnapshot: ActivatedRouteSnapshot,
routerStateSnapshot: RouterStateSnapshot,
) => {
const authService = inject(AuthService);
const cryptoService = inject(CryptoService);
const deviceTrustService = inject(DeviceTrustServiceAbstraction);
const platformUtilService = inject(PlatformUtilsService);
const messagingService = inject(MessagingService);
const router = inject(Router);
const userVerificationService = inject(UserVerificationService);
const vaultTimeoutSettingsService = inject(VaultTimeoutSettingsService);
const accountService = inject(AccountService);
const activeUser = await firstValueFrom(accountService.activeAccount$);
const authStatus = await firstValueFrom(authService.authStatusFor$(activeUser.id));
if (authStatus !== AuthenticationStatus.Locked) {
return router.createUrlTree(["/"]);
}
// if user can't lock, they can't access the lock screen
const canLock = await vaultTimeoutSettingsService.canLock(activeUser.id);
if (!canLock) {
return false;
}
// If legacy user on web, redirect to migration page
if (await cryptoService.isLegacyUser()) {
if (platformUtilService.getClientType() === ClientType.Web) {
return router.createUrlTree(["migrate-legacy-encryption"]);
}
// Log out legacy users on other clients
messagingService.send("logout");
return false;
}
// User is authN and in locked state.
const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$);
// Create special exception which allows users to go from the login-initiated page to the lock page for the approve w/ MP flow
// The MP check is necessary to prevent direct manual navigation from other locked state pages for users who don't have a MP
if (
activatedRouteSnapshot.queryParams["from"] === "login-initiated" &&
tdeEnabled &&
(await userVerificationService.hasMasterPassword())
) {
return true;
}
// If authN user with TDE directly navigates to lock, reject that navigation
const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$);
if (tdeEnabled && !everHadUserKey) {
return false;
}
return true;
};
}