From d825b5c6e539f8d41b32ab625af61eb003320864 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Wed, 13 Aug 2025 11:58:55 -0700 Subject: [PATCH] [PM-24689] Handle possible null active account (#16006) --- .../restricted-item-types.service.spec.ts | 7 ++ .../services/restricted-item-types.service.ts | 64 ++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/libs/common/src/vault/services/restricted-item-types.service.spec.ts b/libs/common/src/vault/services/restricted-item-types.service.spec.ts index 9b549665184..f412de08046 100644 --- a/libs/common/src/vault/services/restricted-item-types.service.spec.ts +++ b/libs/common/src/vault/services/restricted-item-types.service.spec.ts @@ -67,6 +67,13 @@ describe("RestrictedItemTypesService", () => { expect(result).toEqual([]); }); + it("emits empty array if no account is active", async () => { + accountService.activeAccount$ = of(null); + + const result = await firstValueFrom(service.restricted$); + expect(result).toEqual([]); + }); + it("emits empty array if no organizations exist", async () => { organizationService.organizations$.mockReturnValue(of([])); policyService.policiesByType$.mockReturnValue(of([])); diff --git a/libs/common/src/vault/services/restricted-item-types.service.ts b/libs/common/src/vault/services/restricted-item-types.service.ts index 8ccc94d365c..0e4c9b87716 100644 --- a/libs/common/src/vault/services/restricted-item-types.service.ts +++ b/libs/common/src/vault/services/restricted-item-types.service.ts @@ -5,7 +5,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { getUserId } from "@bitwarden/common/auth/services/account.service"; +import { getOptionalUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { CipherType } from "@bitwarden/common/vault/enums"; @@ -32,39 +32,43 @@ export class RestrictedItemTypesService { return of([]); } return this.accountService.activeAccount$.pipe( - getUserId, - switchMap((userId) => - combineLatest([ + getOptionalUserId, + switchMap((userId) => { + if (userId == null) { + return of([]); // No user logged in, no restrictions + } + return combineLatest([ this.organizationService.organizations$(userId), this.policyService.policiesByType$(PolicyType.RestrictedItemTypes, userId), - ]), - ), - map(([orgs, enabledPolicies]) => { - // Helper to extract restricted types, defaulting to [Card] - const restrictedTypes = (p: (typeof enabledPolicies)[number]) => - (p.data as CipherType[]) ?? [CipherType.Card]; + ]).pipe( + map(([orgs, enabledPolicies]) => { + // Helper to extract restricted types, defaulting to [Card] + const restrictedTypes = (p: (typeof enabledPolicies)[number]) => + (p.data as CipherType[]) ?? [CipherType.Card]; - // Union across all enabled policies - const allRestrictedTypes = Array.from( - new Set(enabledPolicies.flatMap(restrictedTypes)), + // Union across all enabled policies + const allRestrictedTypes = Array.from( + new Set(enabledPolicies.flatMap(restrictedTypes)), + ); + + return allRestrictedTypes.map((cipherType) => { + // Determine which orgs allow viewing this type + const allowViewOrgIds = orgs + .filter((org) => { + const orgPolicy = enabledPolicies.find((p) => p.organizationId === org.id); + // no policy for this org => allows everything + if (!orgPolicy) { + return true; + } + // if this type not in their restricted list => they allow it + return !restrictedTypes(orgPolicy).includes(cipherType); + }) + .map((org) => org.id); + + return { cipherType, allowViewOrgIds }; + }); + }), ); - - return allRestrictedTypes.map((cipherType) => { - // Determine which orgs allow viewing this type - const allowViewOrgIds = orgs - .filter((org) => { - const orgPolicy = enabledPolicies.find((p) => p.organizationId === org.id); - // no policy for this org => allows everything - if (!orgPolicy) { - return true; - } - // if this type not in their restricted list => they allow it - return !restrictedTypes(orgPolicy).includes(cipherType); - }) - .map((org) => org.id); - - return { cipherType, allowViewOrgIds }; - }); }), ); }),