mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 01:33:33 +00:00
[AC-1139] Changed canAccessVaultTab function to receive configService
This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
import { Component, Input, OnInit } from "@angular/core";
|
import { Component, Input, OnInit } from "@angular/core";
|
||||||
import { combineLatest, map, Observable } from "rxjs";
|
import { Observable, switchMap } from "rxjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
canAccessAdmin,
|
canAccessAdmin,
|
||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
@@ -28,13 +27,10 @@ export class OrganizationSwitcherComponent implements OnInit {
|
|||||||
loaded = false;
|
loaded = false;
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.organizations$ = combineLatest([
|
this.organizations$ = this.organizationService.memberOrganizations$.pipe(
|
||||||
this.organizationService.memberOrganizations$,
|
switchMap(async (orgs) => {
|
||||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollections, false),
|
const canAccess = await canAccessAdmin(this.i18nService, this.configService);
|
||||||
]).pipe(
|
return canAccess ? orgs.sort(Utils.getSortFunction(this.i18nService, "name")) : orgs;
|
||||||
map(([orgs, flexibleCollectionsEnabled]) => {
|
|
||||||
const canAccess = canAccessAdmin(this.i18nService, flexibleCollectionsEnabled);
|
|
||||||
return canAccess ? orgs.sort(Utils.getSortFunction(this.i18nService, "name")) : [];
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
@@ -45,17 +44,12 @@ export class OrganizationPermissionsGuard implements CanActivate {
|
|||||||
return this.router.createUrlTree(["/"]);
|
return this.router.createUrlTree(["/"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
|
||||||
FeatureFlag.FlexibleCollections,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
const permissionsCallback: (
|
const permissionsCallback: (
|
||||||
organization: Organization,
|
organization: Organization,
|
||||||
flexibleCollectionsEnabled: boolean
|
configService: ConfigServiceAbstraction
|
||||||
) => boolean = route.data?.organizationPermissions;
|
) => Promise<boolean> = route.data?.organizationPermissions;
|
||||||
const hasPermissions =
|
const hasPermissions =
|
||||||
permissionsCallback == null || permissionsCallback(org, flexibleCollectionsEnabled);
|
permissionsCallback == null || (await permissionsCallback(org, this.configService));
|
||||||
|
|
||||||
if (!hasPermissions) {
|
if (!hasPermissions) {
|
||||||
// Handle linkable ciphers for organizations the user only has view access to
|
// Handle linkable ciphers for organizations the user only has view access to
|
||||||
@@ -71,7 +65,7 @@ export class OrganizationPermissionsGuard implements CanActivate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("accessDenied"));
|
this.platformUtilsService.showToast("error", null, this.i18nService.t("accessDenied"));
|
||||||
return canAccessOrgAdmin(org, flexibleCollectionsEnabled)
|
return (await canAccessOrgAdmin(org, this.configService))
|
||||||
? this.router.createUrlTree(["/organizations", org.id])
|
? this.router.createUrlTree(["/organizations", org.id])
|
||||||
: this.router.createUrlTree(["/"]);
|
: this.router.createUrlTree(["/"]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
canAccessOrgAdmin,
|
canAccessOrgAdmin,
|
||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -20,21 +19,17 @@ export class OrganizationRedirectGuard implements CanActivate {
|
|||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
const org = this.organizationService.get(route.params.organizationId);
|
const org = this.organizationService.get(route.params.organizationId);
|
||||||
const flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
|
||||||
FeatureFlag.FlexibleCollections,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
const customRedirect = route.data?.autoRedirectCallback;
|
const customRedirect = route.data?.autoRedirectCallback;
|
||||||
if (customRedirect) {
|
if (customRedirect) {
|
||||||
let redirectPath = customRedirect(org, flexibleCollectionsEnabled);
|
let redirectPath = await customRedirect(org, this.configService);
|
||||||
if (typeof redirectPath === "string") {
|
if (typeof redirectPath === "string") {
|
||||||
redirectPath = [redirectPath];
|
redirectPath = [redirectPath];
|
||||||
}
|
}
|
||||||
return this.router.createUrlTree([state.url, ...redirectPath]);
|
return this.router.createUrlTree([state.url, ...redirectPath]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAccessOrgAdmin(org, flexibleCollectionsEnabled)) {
|
if (await canAccessOrgAdmin(org, this.configService)) {
|
||||||
return this.router.createUrlTree(["/organizations", org.id]);
|
return this.router.createUrlTree(["/organizations", org.id]);
|
||||||
}
|
}
|
||||||
return this.router.createUrlTree(["/"]);
|
return this.router.createUrlTree(["/"]);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
[activeOrganization]="organization"
|
[activeOrganization]="organization"
|
||||||
></app-organization-switcher>
|
></app-organization-switcher>
|
||||||
<bit-tab-nav-bar class="-tw-mb-px">
|
<bit-tab-nav-bar class="-tw-mb-px">
|
||||||
<bit-tab-link *ngIf="canShowVaultTab(organization)" route="vault">{{
|
<bit-tab-link *ngIf="canShowVaultTab(organization) | async" route="vault">{{
|
||||||
"vault" | i18n
|
"vault" | i18n
|
||||||
}}</bit-tab-link>
|
}}</bit-tab-link>
|
||||||
<bit-tab-link *ngIf="canShowMembersTab(organization)" route="members">{{
|
<bit-tab-link *ngIf="canShowMembersTab(organization)" route="members">{{
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
|||||||
this._destroy.complete();
|
this._destroy.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
canShowVaultTab(organization: Organization): boolean {
|
async canShowVaultTab(organization: Organization): Promise<boolean> {
|
||||||
return canAccessVaultTab(organization, this.flexibleCollectionsEnabled);
|
return await canAccessVaultTab(organization, this.configService);
|
||||||
}
|
}
|
||||||
|
|
||||||
canShowSettingsTab(organization: Organization): boolean {
|
canShowSettingsTab(organization: Organization): boolean {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
canAccessSettingsTab,
|
canAccessSettingsTab,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
|
|
||||||
import { OrganizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard";
|
import { OrganizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard";
|
||||||
import { OrganizationRedirectGuard } from "../../admin-console/organizations/guards/org-redirect.guard";
|
import { OrganizationRedirectGuard } from "../../admin-console/organizations/guards/org-redirect.guard";
|
||||||
@@ -78,11 +79,11 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function getOrganizationRoute(
|
async function getOrganizationRoute(
|
||||||
organization: Organization,
|
organization: Organization,
|
||||||
flexibleCollectionsEnabled: boolean
|
configService: ConfigServiceAbstraction
|
||||||
): string {
|
): Promise<string> {
|
||||||
if (canAccessVaultTab(organization, flexibleCollectionsEnabled)) {
|
if (await canAccessVaultTab(organization, configService)) {
|
||||||
return "vault";
|
return "vault";
|
||||||
}
|
}
|
||||||
if (canAccessMembersTab(organization)) {
|
if (canAccessMembersTab(organization)) {
|
||||||
|
|||||||
@@ -22,9 +22,15 @@
|
|||||||
class="nav-item"
|
class="nav-item"
|
||||||
routerLinkActive="active"
|
routerLinkActive="active"
|
||||||
>
|
>
|
||||||
<a class="nav-link" [routerLink]="['/organizations', (organizations$ | async)[0].id]">{{
|
<ng-container *ngIf="{ orgs: organizations$ | async } as data">
|
||||||
"organizations" | i18n
|
<a
|
||||||
}}</a>
|
*ngIf="data.orgs?.length > 0"
|
||||||
|
class="nav-link"
|
||||||
|
[routerLink]="['/organizations', data.orgs[0].id]"
|
||||||
|
>
|
||||||
|
{{ "organizations" | i18n }}
|
||||||
|
</a>
|
||||||
|
</ng-container>
|
||||||
</li>
|
</li>
|
||||||
<ng-container *ngIf="providers.length >= 1">
|
<ng-container *ngIf="providers.length >= 1">
|
||||||
<li class="nav-item" routerLinkActive="active" *ngIf="providers.length == 1">
|
<li class="nav-item" routerLinkActive="active" *ngIf="providers.length == 1">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { combineLatest, map, Observable } from "rxjs";
|
import { map, Observable, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
import {
|
import {
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { Provider } from "@bitwarden/common/models/domain/provider";
|
import { Provider } from "@bitwarden/common/models/domain/provider";
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
@@ -60,13 +59,10 @@ export class NavbarComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.providers = await this.providerService.getAll();
|
this.providers = await this.providerService.getAll();
|
||||||
|
|
||||||
this.organizations$ = combineLatest([
|
this.organizations$ = this.organizationService.memberOrganizations$.pipe(
|
||||||
this.organizationService.memberOrganizations$,
|
switchMap(async (orgs) => {
|
||||||
this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollections, false),
|
const isAdmin = await canAccessAdmin(this.i18nService, this.configService);
|
||||||
]).pipe(
|
return isAdmin ? orgs : [];
|
||||||
map(([organizations, featureFlag]) => {
|
|
||||||
const canAccess = canAccessAdmin(this.i18nService, featureFlag);
|
|
||||||
return canAccess ? organizations : [];
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.canLock$ = this.vaultTimeoutSettingsService
|
this.canLock$ = this.vaultTimeoutSettingsService
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
OrganizationService,
|
OrganizationService,
|
||||||
canAccessVaultTab,
|
canAccessVaultTab,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
|
||||||
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
|
||||||
import { ImportComponent } from "@bitwarden/importer/ui";
|
import { ImportComponent } from "@bitwarden/importer/ui";
|
||||||
|
|
||||||
@@ -22,8 +21,6 @@ export class ImportWebComponent implements OnInit {
|
|||||||
protected loading = false;
|
protected loading = false;
|
||||||
protected disabled = false;
|
protected disabled = false;
|
||||||
|
|
||||||
private flexibleCollectionsEnabled: boolean;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
@@ -31,11 +28,8 @@ export class ImportWebComponent implements OnInit {
|
|||||||
private configService: ConfigServiceAbstraction
|
private configService: ConfigServiceAbstraction
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.routeOrgId = this.route.snapshot.paramMap.get("organizationId");
|
this.routeOrgId = this.route.snapshot.paramMap.get("organizationId");
|
||||||
this.flexibleCollectionsEnabled = await this.configService.getFeatureFlag(
|
|
||||||
FeatureFlag.FlexibleCollections
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +46,7 @@ export class ImportWebComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAccessVaultTab(organization, this.flexibleCollectionsEnabled)) {
|
if (await canAccessVaultTab(organization, this.configService)) {
|
||||||
await this.router.navigate(["organizations", organizationId, "vault"]);
|
await this.router.navigate(["organizations", organizationId, "vault"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
|||||||
protected canDelete$ = this.flexibleCollectionsEnabled$.pipe(
|
protected canDelete$ = this.flexibleCollectionsEnabled$.pipe(
|
||||||
switchMap(async (flexibleCollectionsEnabled) => {
|
switchMap(async (flexibleCollectionsEnabled) => {
|
||||||
return (
|
return (
|
||||||
this.editMode && this.collection?.canDelete(this.organization!, flexibleCollectionsEnabled)
|
this.editMode && this.collection.canDelete(this.organization, flexibleCollectionsEnabled)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
import { map, Observable } from "rxjs";
|
import { map, Observable } from "rxjs";
|
||||||
|
|
||||||
|
import { FeatureFlag } from "../../../enums/feature-flag.enum";
|
||||||
|
import { ConfigServiceAbstraction } from "../../../platform/abstractions/config/config.service.abstraction";
|
||||||
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
||||||
import { Utils } from "../../../platform/misc/utils";
|
import { Utils } from "../../../platform/misc/utils";
|
||||||
import { OrganizationData } from "../../models/data/organization.data";
|
import { OrganizationData } from "../../models/data/organization.data";
|
||||||
import { Organization } from "../../models/domain/organization";
|
import { Organization } from "../../models/domain/organization";
|
||||||
|
|
||||||
export function canAccessVaultTab(org: Organization, flexibleCollectionsEnabled: boolean): boolean {
|
export async function canAccessVaultTab(
|
||||||
|
org: Organization,
|
||||||
|
configService: ConfigServiceAbstraction
|
||||||
|
): Promise<boolean> {
|
||||||
|
const flexibleCollectionsEnabled = await configService.getFeatureFlag(
|
||||||
|
FeatureFlag.FlexibleCollections,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
if (flexibleCollectionsEnabled) {
|
if (flexibleCollectionsEnabled) {
|
||||||
return org.canViewAllCollections;
|
return org.canViewAllCollections;
|
||||||
} else {
|
} else {
|
||||||
@@ -40,14 +50,17 @@ export function canAccessBillingTab(org: Organization): boolean {
|
|||||||
return org.isOwner;
|
return org.isOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canAccessOrgAdmin(org: Organization, flexibleCollectionsEnabled: boolean): boolean {
|
export async function canAccessOrgAdmin(
|
||||||
|
org: Organization,
|
||||||
|
configService: ConfigServiceAbstraction
|
||||||
|
): Promise<boolean> {
|
||||||
return (
|
return (
|
||||||
canAccessMembersTab(org) ||
|
canAccessMembersTab(org) ||
|
||||||
canAccessGroupsTab(org) ||
|
canAccessGroupsTab(org) ||
|
||||||
canAccessReportingTab(org) ||
|
canAccessReportingTab(org) ||
|
||||||
canAccessBillingTab(org) ||
|
canAccessBillingTab(org) ||
|
||||||
canAccessSettingsTab(org) ||
|
canAccessSettingsTab(org) ||
|
||||||
canAccessVaultTab(org, flexibleCollectionsEnabled)
|
(await canAccessVaultTab(org, configService))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,12 +68,18 @@ export function getOrganizationById(id: string) {
|
|||||||
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canAccessAdmin(i18nService: I18nService, flexibleCollectionsEnabled: boolean) {
|
export async function canAccessAdmin(
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
i18nService: I18nService,
|
||||||
orgs
|
configService: ConfigServiceAbstraction
|
||||||
.filter((org) => canAccessOrgAdmin(org, flexibleCollectionsEnabled))
|
) {
|
||||||
.sort(Utils.getSortFunction(i18nService, "name"))
|
return async (orgs: Organization[]): Promise<Organization[]> => {
|
||||||
);
|
const orgsPromises = orgs.map(async (org) => {
|
||||||
|
const canAccess = await canAccessOrgAdmin(org, configService);
|
||||||
|
return canAccess ? org : null;
|
||||||
|
});
|
||||||
|
const results = (await Promise.all(orgsPromises)).filter((org) => org !== null);
|
||||||
|
return results.sort(Utils.getSortFunction(i18nService, "name"));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canAccessImportExport(i18nService: I18nService) {
|
export function canAccessImportExport(i18nService: I18nService) {
|
||||||
|
|||||||
Reference in New Issue
Block a user