diff --git a/libs/angular/src/auth/guards/index.ts b/libs/angular/src/auth/guards/index.ts index 026848c4b08..8a4d0be8167 100644 --- a/libs/angular/src/auth/guards/index.ts +++ b/libs/angular/src/auth/guards/index.ts @@ -1,6 +1,6 @@ export * from "./auth.guard"; export * from "./active-auth.guard"; export * from "./lock.guard"; -export * from "./redirect.guard"; +export * from "./redirect/redirect.guard"; export * from "./tde-decryption-required.guard"; export * from "./unauth.guard"; diff --git a/libs/angular/src/auth/guards/redirect/README.md b/libs/angular/src/auth/guards/redirect/README.md new file mode 100644 index 00000000000..b7977a553b1 --- /dev/null +++ b/libs/angular/src/auth/guards/redirect/README.md @@ -0,0 +1,53 @@ +# Redirect Guard + +The `redirectGuard` redirects the user based on their `AuthenticationStatus`. It is applied to the root route (`/`). + +
+ +### Order of Operations + +The `redirectGuard` will redirect the user based on the following checks, _in order_: + +- **`AuthenticationStatus.LoggedOut`** → redirect to `/login` +- **`AuthenticationStatus.Unlocked`** → redirect to `/vault` +- **`AuthenticationStatus.Locked`** + - **TDE Locked State** → redirect to `/login-initiated` + - A user is in a TDE Locked State if they meet all 3 of the following conditions + 1. Auth status is `Locked` + 2. TDE is enabled + 3. User has never had a user key (that is, user has not unlocked/decrypted yet) + - **Standard Locked State** → redirect to `/lock` + +
+ +| Order | AuthenticationStatus | Redirect To | +| ----- | ------------------------------------------------------------------------------- | ------------------ | +| 1 | `LoggedOut` | `/login` | +| 2 | `Unlocked` | `/vault` | +| 3 | **TDE Locked State**
`Locked` +
`tdeEnabled` +
`!everHadUserKey` | `/login-initiated` | +| 4 | **Standard Locked State**
`Locked` | `/lock` | + +
+ +### Default Routes and Route Overrides + +The default redirect routes are mapped to object properties: + +```typescript +const defaultRoutes: RedirectRoutes = { + loggedIn: "/vault", + loggedOut: "/login", + locked: "/lock", + notDecrypted: "/login-initiated", +}; +``` + +But when applying the guard to the root route, the developer can override specific redirect routes by passing in a custom object. This is useful for subtle differences in client-specific routing: + +```typescript +// app-routing.module.ts (Browser Extension) +{ + path: "", + canActivate: [redirectGuard({ loggedIn: "/tabs/current"})], +} +``` diff --git a/libs/angular/src/auth/guards/redirect.guard.ts b/libs/angular/src/auth/guards/redirect/redirect.guard.ts similarity index 86% rename from libs/angular/src/auth/guards/redirect.guard.ts rename to libs/angular/src/auth/guards/redirect/redirect.guard.ts index b893614b405..45e552639c8 100644 --- a/libs/angular/src/auth/guards/redirect.guard.ts +++ b/libs/angular/src/auth/guards/redirect/redirect.guard.ts @@ -25,12 +25,14 @@ const defaultRoutes: RedirectRoutes = { }; /** - * Guard that consolidates all redirection logic, should be applied to root route. + * Redirects the user to the appropriate route based on their `AuthenticationStatus`. + * This guard should be applied to the root route. * * TODO: This should return Observable once we can get rid of all the promises */ export function redirectGuard(overrides: Partial = {}): CanActivateFn { const routes = { ...defaultRoutes, ...overrides }; + return async (route) => { const authService = inject(AuthService); const keyService = inject(KeyService); @@ -41,16 +43,21 @@ export function redirectGuard(overrides: Partial = {}): CanActiv const authStatus = await authService.getAuthStatus(); + // Logged Out if (authStatus === AuthenticationStatus.LoggedOut) { return router.createUrlTree([routes.loggedOut], { queryParams: route.queryParams }); } + // Unlocked if (authStatus === AuthenticationStatus.Unlocked) { return router.createUrlTree([routes.loggedIn], { queryParams: route.queryParams }); } - // If locked, TDE is enabled, and the user hasn't decrypted yet, then redirect to the - // login decryption options component. + // Locked: TDE Locked State + // - If user meets all 3 of the following conditions: + // 1. Auth status is Locked + // 2. TDE is enabled + // 3. User has never had a user key (has not decrypted yet) const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$); const userId = await firstValueFrom(accountService.activeAccount$.pipe(getUserId)); const everHadUserKey = await firstValueFrom(keyService.everHadUserKey$(userId)); @@ -64,6 +71,7 @@ export function redirectGuard(overrides: Partial = {}): CanActiv return router.createUrlTree([routes.notDecrypted], { queryParams: route.queryParams }); } + // Locked: Standard Locked State if (authStatus === AuthenticationStatus.Locked) { return router.createUrlTree([routes.locked], { queryParams: route.queryParams }); }