diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets-manager.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets-manager.module.ts index 754eca2453..1468af322a 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets-manager.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets-manager.module.ts @@ -5,10 +5,8 @@ import { SharedModule } from "@bitwarden/web-vault/app/shared"; import { LayoutModule } from "./layout/layout.module"; import { SecretsManagerSharedModule } from "./shared/sm-shared.module"; import { SecretsManagerRoutingModule } from "./sm-routing.module"; -import { SMGuard } from "./sm.guard"; @NgModule({ imports: [SharedModule, SecretsManagerSharedModule, SecretsManagerRoutingModule, LayoutModule], - providers: [SMGuard], }) export class SecretsManagerModule {} diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts index 236881c20b..f279314b43 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts @@ -13,59 +13,70 @@ import { ProjectsModule } from "./projects/projects.module"; import { SecretsModule } from "./secrets/secrets.module"; import { ServiceAccountsModule } from "./service-accounts/service-accounts.module"; import { SettingsModule } from "./settings/settings.module"; -import { SMGuard } from "./sm.guard"; +import { canActivateSM } from "./sm.guard"; import { TrashModule } from "./trash/trash.module"; const routes: Routes = [ buildFlaggedRoute("secretsManager", { - path: ":organizationId", - component: LayoutComponent, - canActivate: [AuthGuard, OrganizationPermissionsGuard, SMGuard], - data: { - organizationPermissions: (org: Organization) => org.canAccessSecretsManager, - }, + path: "", children: [ { path: "", - component: NavigationComponent, - outlet: "sidebar", - }, - { - path: "secrets", - loadChildren: () => SecretsModule, - data: { - titleId: "secrets", - }, - }, - { - path: "projects", - loadChildren: () => ProjectsModule, - data: { - titleId: "projects", - }, - }, - { - path: "service-accounts", - loadChildren: () => ServiceAccountsModule, - data: { - titleId: "serviceAccounts", - }, - }, - { - path: "trash", - loadChildren: () => TrashModule, - data: { - titleId: "trash", - }, - }, - { - path: "settings", - loadChildren: () => SettingsModule, - }, - { - path: "", - loadChildren: () => OverviewModule, + canActivate: [canActivateSM], pathMatch: "full", + children: [], + }, + { + path: ":organizationId", + component: LayoutComponent, + canActivate: [AuthGuard, OrganizationPermissionsGuard], + data: { + organizationPermissions: (org: Organization) => org.canAccessSecretsManager, + }, + children: [ + { + path: "", + component: NavigationComponent, + outlet: "sidebar", + }, + { + path: "secrets", + loadChildren: () => SecretsModule, + data: { + titleId: "secrets", + }, + }, + { + path: "projects", + loadChildren: () => ProjectsModule, + data: { + titleId: "projects", + }, + }, + { + path: "service-accounts", + loadChildren: () => ServiceAccountsModule, + data: { + titleId: "serviceAccounts", + }, + }, + { + path: "trash", + loadChildren: () => TrashModule, + data: { + titleId: "trash", + }, + }, + { + path: "settings", + loadChildren: () => SettingsModule, + }, + { + path: "", + loadChildren: () => OverviewModule, + pathMatch: "full", + }, + ], }, ], }), diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts b/bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts index b937c3ec07..340f0484f7 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts @@ -1,10 +1,42 @@ -import { Injectable } from "@angular/core"; -import { ActivatedRouteSnapshot, CanActivate } from "@angular/router"; +import { inject } from "@angular/core"; +import { + ActivatedRouteSnapshot, + CanActivateFn, + createUrlTreeFromSnapshot, + RouterStateSnapshot, +} from "@angular/router"; -@Injectable() -export class SMGuard implements CanActivate { - async canActivate(route: ActivatedRouteSnapshot) { - // TODO: Verify org - return true; +import { AuthGuard } from "@bitwarden/angular/auth/guards/auth.guard"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; + +/** + * Redirects from root `/sm` to first organization with access to SM + */ +export const canActivateSM: CanActivateFn = async ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot +) => { + const syncService = inject(SyncService); + const authService = inject(AuthService); + const orgService = inject(OrganizationService); + const authGuard = inject(AuthGuard); + + /** Workaround to avoid service initialization race condition. */ + if ((await syncService.getLastSync()) == null) { + await syncService.fullSync(false); } -} + + if ((await authService.getAuthStatus()) !== AuthenticationStatus.Unlocked) { + return authGuard.canActivate(route, state); + } + + const orgs = await orgService.getAll(); + const smOrg = orgs.find((o) => o.canAccessSecretsManager); + if (smOrg) { + return createUrlTreeFromSnapshot(route, ["/sm", smOrg.id]); + } + return createUrlTreeFromSnapshot(route, ["/vault"]); +};