mirror of
https://github.com/bitwarden/browser
synced 2026-02-04 10:43:47 +00:00
113 lines
4.6 KiB
TypeScript
113 lines
4.6 KiB
TypeScript
// FIXME: Update this file to be type safe and remove this and next line
|
|
// @ts-strict-ignore
|
|
import { inject } from "@angular/core";
|
|
import {
|
|
ActivatedRouteSnapshot,
|
|
CanActivateFn,
|
|
Router,
|
|
RouterStateSnapshot,
|
|
UrlTree,
|
|
} from "@angular/router";
|
|
import { firstValueFrom } from "rxjs";
|
|
|
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
|
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
|
|
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
|
|
|
export const authGuard: CanActivateFn = async (
|
|
route: ActivatedRouteSnapshot,
|
|
routerState: RouterStateSnapshot,
|
|
): Promise<boolean | UrlTree> => {
|
|
const authService = inject(AuthService);
|
|
const router = inject(Router);
|
|
const messagingService = inject(MessagingService);
|
|
const keyConnectorService = inject(KeyConnectorService);
|
|
const accountService = inject(AccountService);
|
|
const masterPasswordService = inject(MasterPasswordServiceAbstraction);
|
|
|
|
const authStatus = await authService.getAuthStatus();
|
|
|
|
if (authStatus === AuthenticationStatus.LoggedOut) {
|
|
messagingService.send("authBlocked", { url: routerState.url });
|
|
return false;
|
|
}
|
|
|
|
const userId = (await firstValueFrom(accountService.activeAccount$)).id;
|
|
const forceSetPasswordReason = await firstValueFrom(
|
|
masterPasswordService.forceSetPasswordReason$(userId),
|
|
);
|
|
|
|
// User JIT provisioned into a master-password-encryption org
|
|
if (
|
|
authStatus === AuthenticationStatus.Locked &&
|
|
forceSetPasswordReason === ForceSetPasswordReason.SsoNewJitProvisionedUser &&
|
|
!routerState.url.includes("set-initial-password")
|
|
) {
|
|
return router.createUrlTree(["/set-initial-password"]);
|
|
}
|
|
|
|
// TDE Offboarding on untrusted device
|
|
if (
|
|
authStatus === AuthenticationStatus.Locked &&
|
|
forceSetPasswordReason === ForceSetPasswordReason.TdeOffboardingUntrustedDevice &&
|
|
!routerState.url.includes("set-initial-password")
|
|
) {
|
|
return router.createUrlTree(["/set-initial-password"]);
|
|
}
|
|
|
|
// We must add exemptions for the SsoNewJitProvisionedUser and TdeOffboardingUntrustedDevice scenarios as
|
|
// the "set-initial-password" route is guarded by the authGuard.
|
|
if (
|
|
authStatus === AuthenticationStatus.Locked &&
|
|
forceSetPasswordReason !== ForceSetPasswordReason.SsoNewJitProvisionedUser &&
|
|
forceSetPasswordReason !== ForceSetPasswordReason.TdeOffboardingUntrustedDevice
|
|
) {
|
|
if (routerState != null) {
|
|
messagingService.send("lockedUrl", { url: routerState.url });
|
|
}
|
|
// TODO PM-9674: when extension refresh is finished, remove promptBiometric
|
|
// as it has been integrated into the component as a default feature.
|
|
return router.createUrlTree(["lock"], { queryParams: { promptBiometric: true } });
|
|
}
|
|
|
|
// Handle cases where a user needs to set a password when they don't already have one:
|
|
// - TDE org user has been given "manage account recovery" permission
|
|
// - TDE offboarding on a trusted device, where we have access to their encryption key wrap with their new password
|
|
if (
|
|
(forceSetPasswordReason ===
|
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission ||
|
|
forceSetPasswordReason === ForceSetPasswordReason.TdeOffboarding) &&
|
|
!routerState.url.includes("set-initial-password")
|
|
) {
|
|
const route = "/set-initial-password";
|
|
return router.createUrlTree([route]);
|
|
}
|
|
|
|
// Handle cases where a user has a password but needs to set a new one:
|
|
// - Account recovery
|
|
// - Weak Password on login
|
|
if (
|
|
(forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset ||
|
|
forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) &&
|
|
!routerState.url.includes("change-password")
|
|
) {
|
|
const route = "/change-password";
|
|
return router.createUrlTree([route]);
|
|
}
|
|
|
|
// Remove password when Key Connector is enabled
|
|
if (
|
|
forceSetPasswordReason == ForceSetPasswordReason.None &&
|
|
!routerState.url.includes("remove-password") &&
|
|
(await firstValueFrom(keyConnectorService.convertAccountRequired$))
|
|
) {
|
|
return router.createUrlTree(["/remove-password"]);
|
|
}
|
|
|
|
return true;
|
|
};
|