add check for PersonalOwnershipPolicy in vault filters (#9570)

This commit is contained in:
Nick Krantz 2024-06-10 14:25:21 -05:00 committed by GitHub
parent d594b680f9
commit cbc34950fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 129 additions and 35 deletions

View File

@ -3,6 +3,8 @@ import { FormBuilder } from "@angular/forms";
import { BehaviorSubject, skipWhile } from "rxjs"; import { BehaviorSubject, skipWhile } from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ProductType } from "@bitwarden/common/enums"; import { ProductType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -23,6 +25,7 @@ describe("VaultPopupListFiltersService", () => {
const folderViews$ = new BehaviorSubject([]); const folderViews$ = new BehaviorSubject([]);
const cipherViews$ = new BehaviorSubject({}); const cipherViews$ = new BehaviorSubject({});
const decryptedCollections$ = new BehaviorSubject<CollectionView[]>([]); const decryptedCollections$ = new BehaviorSubject<CollectionView[]>([]);
const policyAppliesToActiveUser$ = new BehaviorSubject<boolean>(false);
const collectionService = { const collectionService = {
decryptedCollections$, decryptedCollections$,
@ -45,9 +48,15 @@ describe("VaultPopupListFiltersService", () => {
t: (key: string) => key, t: (key: string) => key,
} as I18nService; } as I18nService;
const policyService = {
policyAppliesToActiveUser$: jest.fn(() => policyAppliesToActiveUser$),
};
beforeEach(() => { beforeEach(() => {
memberOrganizations$.next([]); memberOrganizations$.next([]);
decryptedCollections$.next([]); decryptedCollections$.next([]);
policyAppliesToActiveUser$.next(false);
policyService.policyAppliesToActiveUser$.mockClear();
collectionService.getAllNested = () => Promise.resolve([]); collectionService.getAllNested = () => Promise.resolve([]);
TestBed.configureTestingModule({ TestBed.configureTestingModule({
@ -72,6 +81,10 @@ describe("VaultPopupListFiltersService", () => {
provide: CollectionService, provide: CollectionService,
useValue: collectionService, useValue: collectionService,
}, },
{
provide: PolicyService,
useValue: policyService,
},
{ provide: FormBuilder, useClass: FormBuilder }, { provide: FormBuilder, useClass: FormBuilder },
], ],
}); });
@ -127,6 +140,65 @@ describe("VaultPopupListFiltersService", () => {
}); });
}); });
describe("PersonalOwnership policy", () => {
it('calls policyAppliesToActiveUser$ with "PersonalOwnership"', () => {
expect(policyService.policyAppliesToActiveUser$).toHaveBeenCalledWith(
PolicyType.PersonalOwnership,
);
});
it("returns an empty array when the policy applies and there is a single organization", (done) => {
policyAppliesToActiveUser$.next(true);
memberOrganizations$.next([
{ name: "bobby's org", id: "1234-3323-23223" },
] as Organization[]);
service.organizations$.subscribe((organizations) => {
expect(organizations).toEqual([]);
done();
});
});
it('adds "myVault" when the policy does not apply and there are multiple organizations', (done) => {
policyAppliesToActiveUser$.next(false);
const orgs = [
{ name: "bobby's org", id: "1234-3323-23223" },
{ name: "alice's org", id: "2223-4343-99888" },
] as Organization[];
memberOrganizations$.next(orgs);
service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([
"myVault",
"alice's org",
"bobby's org",
]);
done();
});
});
it('does not add "myVault" the policy applies and there are multiple organizations', (done) => {
policyAppliesToActiveUser$.next(true);
const orgs = [
{ name: "bobby's org", id: "1234-3323-23223" },
{ name: "alice's org", id: "2223-3242-99888" },
{ name: "catherine's org", id: "77733-4343-99888" },
] as Organization[];
memberOrganizations$.next(orgs);
service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([
"alice's org",
"bobby's org",
"catherine's org",
]);
done();
});
});
});
describe("icons", () => { describe("icons", () => {
it("sets family icon for family organizations", (done) => { it("sets family icon for family organizations", (done) => {
const orgs = [ const orgs = [

View File

@ -13,6 +13,8 @@ import {
import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model"; import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ProductType } from "@bitwarden/common/enums"; import { ProductType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -88,6 +90,7 @@ export class VaultPopupListFiltersService {
private i18nService: I18nService, private i18nService: I18nService,
private collectionService: CollectionService, private collectionService: CollectionService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private policyService: PolicyService,
) { ) {
this.filterForm.controls.organization.valueChanges this.filterForm.controls.organization.valueChanges
.pipe(takeUntilDestroyed()) .pipe(takeUntilDestroyed())
@ -167,21 +170,40 @@ export class VaultPopupListFiltersService {
/** /**
* Organization array structured to be directly passed to `ChipSelectComponent` * Organization array structured to be directly passed to `ChipSelectComponent`
*/ */
organizations$: Observable<ChipSelectOption<Organization>[]> = organizations$: Observable<ChipSelectOption<Organization>[]> = combineLatest([
this.organizationService.memberOrganizations$.pipe( this.organizationService.memberOrganizations$,
map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))), this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
map((orgs) => { ]).pipe(
map(([orgs, personalOwnershipApplies]): [Organization[], boolean] => [
orgs.sort(Utils.getSortFunction(this.i18nService, "name")),
personalOwnershipApplies,
]),
map(([orgs, personalOwnershipApplies]) => {
// When there are no organizations return an empty array,
// resulting in the org filter being hidden
if (!orgs.length) { if (!orgs.length) {
return []; return [];
} }
return [ // When there is only one organization and personal ownership policy applies,
// When the user is a member of an organization, make the "My Vault" option available // return an empty array, resulting in the org filter being hidden
{ if (orgs.length === 1 && personalOwnershipApplies) {
return [];
}
const myVaultOrg: ChipSelectOption<Organization>[] = [];
// Only add "My vault" if personal ownership policy does not apply
if (!personalOwnershipApplies) {
myVaultOrg.push({
value: { id: MY_VAULT_ID } as Organization, value: { id: MY_VAULT_ID } as Organization,
label: this.i18nService.t("myVault"), label: this.i18nService.t("myVault"),
icon: "bwi-user", icon: "bwi-user",
}, });
}
return [
...myVaultOrg,
...orgs.map((org) => { ...orgs.map((org) => {
let icon = "bwi-business"; let icon = "bwi-business";