diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 555e3a13fa0..15fb6b5f78a 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -21,11 +21,11 @@ import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextInternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; +import { DefaultvNextOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-vnext-organization.service"; import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service"; @@ -328,7 +328,7 @@ export default class MainBackground { sendStateProvider: SendStateProvider; fileUploadService: FileUploadServiceAbstraction; cipherFileUploadService: CipherFileUploadServiceAbstraction; - organizationService: InternalOrganizationServiceAbstraction; + organizationService: vNextInternalOrganizationServiceAbstraction; providerService: ProviderServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction; userVerificationService: UserVerificationServiceAbstraction; @@ -668,7 +668,7 @@ export default class MainBackground { this.appIdService = new AppIdService(this.storageService, this.logService); this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); - this.organizationService = new OrganizationService(this.stateProvider); + this.organizationService = new DefaultvNextOrganizationService(this.stateProvider); this.policyService = new PolicyService(this.stateProvider, this.organizationService); this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService( @@ -1246,6 +1246,7 @@ export default class MainBackground { this.cipherAuthorizationService = new DefaultCipherAuthorizationService( this.collectionService, this.organizationService, + this.accountService, ); this.inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService(); diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 5b27833636f..cfee2fe6fe6 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -32,8 +32,8 @@ import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarde import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; -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 { DefaultvNextOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-vnext-organization.service"; import { AccountService, AccountService as AccountServiceAbstraction, @@ -376,7 +376,7 @@ const safeProviders: SafeProvider[] = [ provide: VaultFilterService, useClass: VaultFilterService, deps: [ - OrganizationService, + DefaultvNextOrganizationService, FolderServiceAbstraction, CipherService, CollectionService, diff --git a/apps/browser/src/vault/popup/components/vault/collections.component.ts b/apps/browser/src/vault/popup/components/vault/collections.component.ts index 407f87e996c..fbe92e8e81a 100644 --- a/apps/browser/src/vault/popup/components/vault/collections.component.ts +++ b/apps/browser/src/vault/popup/components/vault/collections.component.ts @@ -5,7 +5,7 @@ import { first } from "rxjs/operators"; import { CollectionService } from "@bitwarden/admin-console/common"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -24,7 +24,7 @@ export class CollectionsComponent extends BaseCollectionsComponent implements On platformUtilsService: PlatformUtilsService, i18nService: I18nService, cipherService: CipherService, - organizationService: OrganizationService, + organizationService: vNextOrganizationService, private route: ActivatedRoute, private location: Location, logService: LogService, diff --git a/apps/browser/src/vault/popup/components/vault/share.component.ts b/apps/browser/src/vault/popup/components/vault/share.component.ts index 8e061665b73..0260587efd7 100644 --- a/apps/browser/src/vault/popup/components/vault/share.component.ts +++ b/apps/browser/src/vault/popup/components/vault/share.component.ts @@ -4,7 +4,7 @@ import { first } from "rxjs/operators"; import { CollectionService } from "@bitwarden/admin-console/common"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -25,7 +25,7 @@ export class ShareComponent extends BaseShareComponent implements OnInit { cipherService: CipherService, private route: ActivatedRoute, private router: Router, - organizationService: OrganizationService, + organizationService: vNextOrganizationService, accountService: AccountService, ) { super( diff --git a/apps/browser/src/vault/services/vault-filter.service.ts b/apps/browser/src/vault/services/vault-filter.service.ts index ba1d11f5d27..d2f423ae613 100644 --- a/apps/browser/src/vault/services/vault-filter.service.ts +++ b/apps/browser/src/vault/services/vault-filter.service.ts @@ -3,7 +3,7 @@ import { CollectionService } from "@bitwarden/admin-console/common"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { StateProvider } from "@bitwarden/common/platform/state"; @@ -18,13 +18,13 @@ export class VaultFilterService extends BaseVaultFilterService { myVault = "myVault"; constructor( - organizationService: OrganizationService, + organizationService: vNextOrganizationService, folderService: FolderService, cipherService: CipherService, collectionService: CollectionService, policyService: PolicyService, stateProvider: StateProvider, - private accountService: AccountService, + accountService: AccountService, ) { super( organizationService, @@ -33,11 +33,12 @@ export class VaultFilterService extends BaseVaultFilterService { collectionService, policyService, stateProvider, + accountService, ); this.vaultFilter.myVaultOnly = false; this.vaultFilter.selectedOrganizationId = null; - this.accountService.activeAccount$.subscribe((account) => { + accountService.activeAccount$.subscribe((account) => { this.setVaultFilter(this.allVaults); }); } diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 2a3d5d85408..a0abaa4ceec 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -14,7 +14,7 @@ import { UserApiLoginCredentials, } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -68,7 +68,7 @@ export class LoginCommand { protected syncService: SyncService, protected keyConnectorService: KeyConnectorService, protected policyApiService: PolicyApiServiceAbstraction, - protected orgService: OrganizationService, + protected orgService: vNextOrganizationService, protected logoutCallback: () => Promise, protected kdfConfigService: KdfConfigService, ) {} diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 1a835befd01..ae3406b459d 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; @@ -61,7 +61,7 @@ export class GetCommand extends DownloadCommand { encryptService: EncryptService, private searchService: SearchService, protected apiService: ApiService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private eventCollectionService: EventCollectionService, private accountProfileService: BillingAccountProfileStateService, private accountService: AccountService, @@ -478,10 +478,18 @@ export class GetCommand extends DownloadCommand { private async getOrganization(id: string) { let org: Organization = null; + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + if (!userId) { + return Response.badRequest("No user found."); + } if (Utils.isGuid(id)) { - org = await this.organizationService.getFromState(id); + org = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === id))), + ); } else if (id.trim() !== "") { - let orgs = await firstValueFrom(this.organizationService.organizations$); + let orgs = await firstValueFrom(this.organizationService.organizations$(userId)); orgs = CliUtils.searchOrganizations(orgs, id); if (orgs.length > 1) { return Response.multipleResults(orgs.map((c) => c.id)); diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 9cb36f71496..3b2a04566f4 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,4 +1,4 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { OrganizationUserApiService, @@ -11,7 +11,8 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { EventType } from "@bitwarden/common/enums"; import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -33,11 +34,12 @@ export class ListCommand { private cipherService: CipherService, private folderService: FolderService, private collectionService: CollectionService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private searchService: SearchService, private organizationUserApiService: OrganizationUserApiService, private apiService: ApiService, private eventCollectionService: EventCollectionService, + private accountService: AccountService, ) {} async run(object: string, cmdOptions: Record): Promise { @@ -172,7 +174,15 @@ export class ListCommand { if (!Utils.isGuid(options.organizationId)) { return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - const organization = await this.organizationService.getFromState(options.organizationId); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + if (!userId) { + return Response.badRequest("No user found."); + } + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizatons) => organizatons.find((o) => o.id == options.organizationId))), + ); if (organization == null) { return Response.error("Organization not found."); } @@ -205,7 +215,15 @@ export class ListCommand { if (!Utils.isGuid(options.organizationId)) { return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - const organization = await this.organizationService.getFromState(options.organizationId); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + if (!userId) { + return Response.badRequest("No user found."); + } + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizatons) => organizatons.find((o) => o.id == options.organizationId))), + ); if (organization == null) { return Response.error("Organization not found."); } @@ -231,7 +249,11 @@ export class ListCommand { } private async listOrganizations(options: Options) { - let organizations = await firstValueFrom(this.organizationService.memberOrganizations$); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + if (!userId) { + return Response.badRequest("No user found."); + } + let organizations = await firstValueFrom(this.organizationService.memberOrganizations$(userId)); if (options.search != null && options.search.trim() !== "") { organizations = CliUtils.searchOrganizations(organizations, options.search); diff --git a/apps/cli/src/oss-serve-configurator.ts b/apps/cli/src/oss-serve-configurator.ts index 71c372ef301..b932b29c793 100644 --- a/apps/cli/src/oss-serve-configurator.ts +++ b/apps/cli/src/oss-serve-configurator.ts @@ -76,6 +76,7 @@ export class OssServeConfigurator { this.serviceContainer.organizationUserApiService, this.serviceContainer.apiService, this.serviceContainer.eventCollectionService, + this.serviceContainer.accountService, ); this.createCommand = new CreateCommand( this.serviceContainer.cipherService, diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 2afbae0782f..3f3196f79e8 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -25,8 +25,8 @@ import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction"; +import { DefaultvNextOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-vnext-organization.service"; import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; import { ProviderApiService } from "@bitwarden/common/admin-console/services/provider/provider-api.service"; @@ -237,7 +237,8 @@ export class ServiceContainer { stateService: StateService; autofillSettingsService: AutofillSettingsServiceAbstraction; domainSettingsService: DomainSettingsService; - organizationService: OrganizationService; + organizationService: DefaultvNextOrganizationService; + defaultvNextOrganizationService: DefaultvNextOrganizationService; providerService: ProviderService; twoFactorService: TwoFactorService; folderApiService: FolderApiService; @@ -449,7 +450,7 @@ export class ServiceContainer { this.biometricStateService = new DefaultBiometricStateService(this.stateProvider); this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); - this.organizationService = new OrganizationService(this.stateProvider); + this.organizationService = new DefaultvNextOrganizationService(this.stateProvider); this.policyService = new PolicyService(this.stateProvider, this.organizationService); this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService( @@ -817,6 +818,7 @@ export class ServiceContainer { this.cipherAuthorizationService = new DefaultCipherAuthorizationService( this.collectionService, this.organizationService, + this.accountService, ); } diff --git a/apps/cli/src/tools/import.command.ts b/apps/cli/src/tools/import.command.ts index a71c9177d29..9087db01d68 100644 --- a/apps/cli/src/tools/import.command.ts +++ b/apps/cli/src/tools/import.command.ts @@ -2,8 +2,10 @@ // @ts-strict-ignore import { OptionValues } from "commander"; import * as inquirer from "inquirer"; +import { firstValueFrom, map } from "rxjs"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { ImportServiceAbstraction, ImportType } from "@bitwarden/importer/core"; @@ -14,14 +16,25 @@ import { CliUtils } from "../utils"; export class ImportCommand { constructor( private importService: ImportServiceAbstraction, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private syncService: SyncService, + private accountService: AccountService, ) {} async run(format: ImportType, filepath: string, options: OptionValues): Promise { const organizationId = options.organizationid; if (organizationId != null) { - const organization = await this.organizationService.getFromState(organizationId); + const userId = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.id)), + ); + if (!userId) { + return Response.badRequest("No user found."); + } + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === organizationId))), + ); if (organization == null) { return Response.badRequest( diff --git a/apps/cli/src/vault.program.ts b/apps/cli/src/vault.program.ts index 1cdf23bcd89..df55b41aa10 100644 --- a/apps/cli/src/vault.program.ts +++ b/apps/cli/src/vault.program.ts @@ -113,6 +113,7 @@ export class VaultProgram extends BaseProgram { this.serviceContainer.organizationUserApiService, this.serviceContainer.apiService, this.serviceContainer.eventCollectionService, + this.serviceContainer.accountService, ); const response = await command.run(object, cmd); @@ -448,6 +449,7 @@ export class VaultProgram extends BaseProgram { this.serviceContainer.importService, this.serviceContainer.organizationService, this.serviceContainer.syncService, + this.serviceContainer.accountService, ); const response = await command.run(format, filepath, options); this.processResponse(response); diff --git a/apps/cli/src/vault/create.command.ts b/apps/cli/src/vault/create.command.ts index aa01ec3c491..26754eff168 100644 --- a/apps/cli/src/vault/create.command.ts +++ b/apps/cli/src/vault/create.command.ts @@ -7,7 +7,7 @@ import { firstValueFrom, map } from "rxjs"; import { CollectionRequest } from "@bitwarden/admin-console/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; @@ -38,7 +38,7 @@ export class CreateCommand { private apiService: ApiService, private folderApiService: FolderApiServiceAbstraction, private accountProfileService: BillingAccountProfileStateService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private accountService: AccountService, ) {} @@ -200,7 +200,17 @@ export class CreateCommand { if (orgKey == null) { throw new Error("No encryption key for this organization."); } - const organization = await this.organizationService.get(req.organizationId); + const userId = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.id)), + ); + if (!userId) { + return Response.badRequest("No user found."); + } + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === req.organizationId))), + ); const currentOrgUserId = organization.organizationUserId; const groups = diff --git a/apps/desktop/src/vault/app/vault/collections.component.ts b/apps/desktop/src/vault/app/vault/collections.component.ts index e7684c3c07a..e85073b4d2e 100644 --- a/apps/desktop/src/vault/app/vault/collections.component.ts +++ b/apps/desktop/src/vault/app/vault/collections.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { CollectionService } from "@bitwarden/admin-console/common"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -20,7 +20,7 @@ export class CollectionsComponent extends BaseCollectionsComponent { i18nService: I18nService, collectionService: CollectionService, platformUtilsService: PlatformUtilsService, - organizationService: OrganizationService, + organizationService: vNextOrganizationService, logService: LogService, accountService: AccountService, toastService: ToastService, diff --git a/apps/desktop/src/vault/app/vault/share.component.ts b/apps/desktop/src/vault/app/vault/share.component.ts index 6926e7e2abf..23a8d293a75 100644 --- a/apps/desktop/src/vault/app/vault/share.component.ts +++ b/apps/desktop/src/vault/app/vault/share.component.ts @@ -3,7 +3,7 @@ import { Component } from "@angular/core"; import { CollectionService } from "@bitwarden/admin-console/common"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -21,7 +21,7 @@ export class ShareComponent extends BaseShareComponent { collectionService: CollectionService, platformUtilsService: PlatformUtilsService, logService: LogService, - organizationService: OrganizationService, + organizationService: vNextOrganizationService, accountService: AccountService, private modalRef: ModalRef, ) { diff --git a/bitwarden_license/bit-cli/src/admin-console/device-approval/approve-all.command.ts b/bitwarden_license/bit-cli/src/admin-console/device-approval/approve-all.command.ts index db63a3c1c68..512f115cf2b 100644 --- a/bitwarden_license/bit-cli/src/admin-console/device-approval/approve-all.command.ts +++ b/bitwarden_license/bit-cli/src/admin-console/device-approval/approve-all.command.ts @@ -1,11 +1,12 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { OrganizationAuthRequestService } from "@bitwarden/bit-common/admin-console/auth-requests"; import { Response } from "@bitwarden/cli/models/response"; import { MessageResponse } from "@bitwarden/cli/models/response/message.response"; -import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ServiceContainer } from "../../service-container"; @@ -13,7 +14,8 @@ import { ServiceContainer } from "../../service-container"; export class ApproveAllCommand { constructor( private organizationAuthRequestService: OrganizationAuthRequestService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, + private accountService: AccountService, ) {} async run(organizationId: string): Promise { @@ -25,7 +27,12 @@ export class ApproveAllCommand { return Response.badRequest("`" + organizationId + "` is not a GUID."); } - const organization = await firstValueFrom(this.organizationService.get$(organizationId)); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === organizationId))), + ); if (!organization?.canManageUsersPassword) { return Response.error( "You do not have permission to approve pending device authorization requests.", @@ -58,6 +65,7 @@ export class ApproveAllCommand { return new ApproveAllCommand( serviceContainer.organizationAuthRequestService, serviceContainer.organizationService, + serviceContainer.accountService, ); } } diff --git a/bitwarden_license/bit-cli/src/admin-console/device-approval/approve.command.ts b/bitwarden_license/bit-cli/src/admin-console/device-approval/approve.command.ts index dc6a6d8e906..611e82001ca 100644 --- a/bitwarden_license/bit-cli/src/admin-console/device-approval/approve.command.ts +++ b/bitwarden_license/bit-cli/src/admin-console/device-approval/approve.command.ts @@ -1,7 +1,8 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { Response } from "@bitwarden/cli/models/response"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { DefaultvNextOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-vnext-organization.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests"; @@ -9,8 +10,9 @@ import { ServiceContainer } from "../../service-container"; export class ApproveCommand { constructor( - private organizationService: OrganizationService, + private organizationService: DefaultvNextOrganizationService, private organizationAuthRequestService: OrganizationAuthRequestService, + private accountService: AccountService, ) {} async run(organizationId: string, id: string): Promise { @@ -30,7 +32,17 @@ export class ApproveCommand { return Response.badRequest("`" + id + "` is not a GUID."); } - const organization = await firstValueFrom(this.organizationService.get$(organizationId)); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + + if (!userId) { + return Response.badRequest("No user found."); + } + + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations?.find((o) => o.id === organizationId))), + ); if (!organization?.canManageUsersPassword) { return Response.error( "You do not have permission to approve pending device authorization requests.", @@ -57,6 +69,7 @@ export class ApproveCommand { return new ApproveCommand( serviceContainer.organizationService, serviceContainer.organizationAuthRequestService, + serviceContainer.accountService, ); } } diff --git a/bitwarden_license/bit-cli/src/admin-console/device-approval/deny-all.command.ts b/bitwarden_license/bit-cli/src/admin-console/device-approval/deny-all.command.ts index f5dff801f27..3a7ac682c95 100644 --- a/bitwarden_license/bit-cli/src/admin-console/device-approval/deny-all.command.ts +++ b/bitwarden_license/bit-cli/src/admin-console/device-approval/deny-all.command.ts @@ -1,10 +1,11 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { Response } from "@bitwarden/cli/models/response"; import { MessageResponse } from "@bitwarden/cli/models/response/message.response"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests"; @@ -12,8 +13,9 @@ import { ServiceContainer } from "../../service-container"; export class DenyAllCommand { constructor( - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private organizationAuthRequestService: OrganizationAuthRequestService, + private accountService: AccountService, ) {} async run(organizationId: string): Promise { @@ -25,7 +27,17 @@ export class DenyAllCommand { return Response.badRequest("`" + organizationId + "` is not a GUID."); } - const organization = await firstValueFrom(this.organizationService.get$(organizationId)); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + + if (!userId) { + return Response.badRequest("No user found."); + } + + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === organizationId))), + ); if (!organization?.canManageUsersPassword) { return Response.error( "You do not have permission to approve pending device authorization requests.", @@ -54,6 +66,7 @@ export class DenyAllCommand { return new DenyAllCommand( serviceContainer.organizationService, serviceContainer.organizationAuthRequestService, + serviceContainer.accountService, ); } } diff --git a/bitwarden_license/bit-cli/src/admin-console/device-approval/deny.command.ts b/bitwarden_license/bit-cli/src/admin-console/device-approval/deny.command.ts index 58c1c576433..a6b26b60d51 100644 --- a/bitwarden_license/bit-cli/src/admin-console/device-approval/deny.command.ts +++ b/bitwarden_license/bit-cli/src/admin-console/device-approval/deny.command.ts @@ -1,7 +1,8 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { Response } from "@bitwarden/cli/models/response"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests"; @@ -9,8 +10,9 @@ import { ServiceContainer } from "../../service-container"; export class DenyCommand { constructor( - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private organizationAuthRequestService: OrganizationAuthRequestService, + private accountServcie: AccountService, ) {} async run(organizationId: string, id: string): Promise { @@ -30,7 +32,17 @@ export class DenyCommand { return Response.badRequest("`" + id + "` is not a GUID."); } - const organization = await firstValueFrom(this.organizationService.get$(organizationId)); + const userId = await firstValueFrom(this.accountServcie.activeAccount$.pipe(map((a) => a?.id))); + + if (!userId) { + return Response.badRequest("No user found."); + } + + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === organizationId))), + ); if (!organization?.canManageUsersPassword) { return Response.error( "You do not have permission to approve pending device authorization requests.", @@ -57,6 +69,7 @@ export class DenyCommand { return new DenyCommand( serviceContainer.organizationService, serviceContainer.organizationAuthRequestService, + serviceContainer.accountService, ); } } diff --git a/bitwarden_license/bit-cli/src/admin-console/device-approval/list.command.ts b/bitwarden_license/bit-cli/src/admin-console/device-approval/list.command.ts index 972be460df7..cac6d049367 100644 --- a/bitwarden_license/bit-cli/src/admin-console/device-approval/list.command.ts +++ b/bitwarden_license/bit-cli/src/admin-console/device-approval/list.command.ts @@ -1,9 +1,10 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { OrganizationAuthRequestService } from "@bitwarden/bit-common/admin-console/auth-requests"; import { Response } from "@bitwarden/cli/models/response"; import { ListResponse } from "@bitwarden/cli/models/response/list.response"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ServiceContainer } from "../../service-container"; @@ -13,7 +14,8 @@ import { PendingAuthRequestResponse } from "./pending-auth-request.response"; export class ListCommand { constructor( private organizationAuthRequestService: OrganizationAuthRequestService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, + private accountService: AccountService, ) {} async run(organizationId: string): Promise { @@ -25,7 +27,17 @@ export class ListCommand { return Response.badRequest("`" + organizationId + "` is not a GUID."); } - const organization = await firstValueFrom(this.organizationService.get$(organizationId)); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + + if (!userId) { + return Response.badRequest("No user found."); + } + + const organization = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(map((organizations) => organizations.find((o) => o.id === organizationId))), + ); if (!organization?.canManageUsersPassword) { return Response.error( "You do not have permission to approve pending device authorization requests.", @@ -46,6 +58,7 @@ export class ListCommand { return new ListCommand( serviceContainer.organizationAuthRequestService, serviceContainer.organizationService, + serviceContainer.accountService, ); } } diff --git a/libs/angular/src/admin-console/components/collections.component.ts b/libs/angular/src/admin-console/components/collections.component.ts index 0b19935985a..ec26dc0bea5 100644 --- a/libs/angular/src/admin-console/components/collections.component.ts +++ b/libs/angular/src/admin-console/components/collections.component.ts @@ -4,7 +4,7 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { firstValueFrom, map } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -34,7 +34,7 @@ export class CollectionsComponent implements OnInit { protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, protected cipherService: CipherService, - protected organizationService: OrganizationService, + protected organizationService: vNextOrganizationService, private logService: LogService, private accountService: AccountService, private toastService: ToastService, @@ -63,7 +63,15 @@ export class CollectionsComponent implements OnInit { } if (this.organization == null) { - this.organization = await this.organizationService.get(this.cipher.organizationId); + this.organization = await firstValueFrom( + this.organizationService + .organizations$(activeUserId) + .pipe( + map((organizations) => + organizations.find((org) => org.id === this.cipher.organizationId), + ), + ), + ); } } diff --git a/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts b/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts index cebd81846c1..8a7b00db898 100644 --- a/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts +++ b/libs/angular/src/billing/components/add-account-credit-dialog/add-account-credit-dialog.component.ts @@ -3,10 +3,10 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { Component, ElementRef, Inject, OnInit, ViewChild } from "@angular/core"; import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; @@ -67,7 +67,7 @@ export class AddAccountCreditDialogComponent implements OnInit { private configService: ConfigService, @Inject(DIALOG_DATA) private dialogParams: AddAccountCreditDialogParams, private dialogRef: DialogRef, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private platformUtilsService: PlatformUtilsService, private providerService: ProviderService, ) { @@ -105,7 +105,16 @@ export class AddAccountCreditDialogComponent implements OnInit { this.formGroup.patchValue({ creditAmount: 20.0, }); - this.organization = await this.organizationService.get(this.dialogParams.organizationId); + this.user = await firstValueFrom(this.accountService.activeAccount$); + this.organization = await firstValueFrom( + this.organizationService + .organizations$(this.user.id) + .pipe( + map((organizations) => + organizations.find((org) => org.id === this.dialogParams.organizationId), + ), + ), + ); payPalCustomField = "organization_id:" + this.organization.id; this.payPalConfig.subject = this.organization.name; } else if (this.dialogParams.providerId) { @@ -119,7 +128,6 @@ export class AddAccountCreditDialogComponent implements OnInit { this.formGroup.patchValue({ creditAmount: 10.0, }); - this.user = await firstValueFrom(this.accountService.activeAccount$); payPalCustomField = "user_id:" + this.user.id; this.payPalConfig.subject = this.user.email; } diff --git a/libs/angular/src/components/share.component.ts b/libs/angular/src/components/share.component.ts index 37dec53b9c7..f618ed515e7 100644 --- a/libs/angular/src/components/share.component.ts +++ b/libs/angular/src/components/share.component.ts @@ -4,7 +4,7 @@ import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angu import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -37,7 +37,7 @@ export class ShareComponent implements OnInit, OnDestroy { protected i18nService: I18nService, protected cipherService: CipherService, private logService: LogService, - protected organizationService: OrganizationService, + protected organizationService: vNextOrganizationService, protected accountService: AccountService, ) {} @@ -54,7 +54,11 @@ export class ShareComponent implements OnInit, OnDestroy { const allCollections = await this.collectionService.getAllDecrypted(); this.writeableCollections = allCollections.map((c) => c).filter((c) => !c.readOnly); - this.organizations$ = this.organizationService.memberOrganizations$.pipe( + const userId = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((account) => account?.id)), + ); + + this.organizations$ = this.organizationService.memberOrganizations$(userId).pipe( map((orgs) => { return orgs .filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed) diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 149d553696e..9a15de0c12c 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -53,6 +53,10 @@ import { InternalOrganizationServiceAbstraction, OrganizationService as OrganizationServiceAbstraction, } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { + vNextInternalOrganizationServiceAbstraction, + vNextOrganizationService as vNextOrganizationServiceAbstraction, +} from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction"; import { OrgDomainInternalServiceAbstraction, @@ -66,6 +70,7 @@ import { } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; +import { DefaultvNextOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-vnext-organization.service"; import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; import { OrgDomainApiService } from "@bitwarden/common/admin-console/services/organization-domain/org-domain-api.service"; @@ -725,7 +730,7 @@ const safeProviders: SafeProvider[] = [ StateServiceAbstraction, ProviderServiceAbstraction, FolderApiServiceAbstraction, - InternalOrganizationServiceAbstraction, + vNextInternalOrganizationServiceAbstraction, SendApiServiceAbstraction, UserDecryptionOptionsServiceAbstraction, AvatarServiceAbstraction, @@ -914,7 +919,7 @@ const safeProviders: SafeProvider[] = [ deps: [ CipherServiceAbstraction, StateProvider, - OrganizationServiceAbstraction, + vNextOrganizationServiceAbstraction, EventUploadServiceAbstraction, AuthServiceAbstraction, AccountServiceAbstraction, @@ -923,7 +928,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: InternalPolicyService, useClass: PolicyService, - deps: [StateProvider, OrganizationServiceAbstraction], + deps: [StateProvider, vNextOrganizationServiceAbstraction], }), safeProvider({ provide: PolicyServiceAbstraction, @@ -959,7 +964,7 @@ const safeProviders: SafeProvider[] = [ ApiServiceAbstraction, TokenServiceAbstraction, LogService, - OrganizationServiceAbstraction, + vNextOrganizationServiceAbstraction, KeyGenerationServiceAbstraction, LOGOUT_CALLBACK, StateProvider, @@ -991,6 +996,16 @@ const safeProviders: SafeProvider[] = [ provide: OrganizationServiceAbstraction, useExisting: InternalOrganizationServiceAbstraction, }), + safeProvider({ + provide: vNextInternalOrganizationServiceAbstraction, + useClass: DefaultvNextOrganizationService, + deps: [StateProvider], + }), + safeProvider({ + provide: vNextOrganizationServiceAbstraction, + useExisting: vNextInternalOrganizationServiceAbstraction, + }), + safeProvider({ provide: OrganizationUserApiService, useClass: DefaultOrganizationUserApiService, @@ -1396,7 +1411,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: CipherAuthorizationService, useClass: DefaultCipherAuthorizationService, - deps: [CollectionService, OrganizationServiceAbstraction], + deps: [CollectionService, vNextOrganizationServiceAbstraction, AccountServiceAbstraction], }), safeProvider({ provide: AuthRequestApiService, diff --git a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts index a2b624876be..84529a1569e 100644 --- a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts +++ b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts @@ -4,13 +4,11 @@ import { Injectable } from "@angular/core"; import { firstValueFrom, from, map, mergeMap, Observable } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { - isMember, - OrganizationService, -} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -33,12 +31,13 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti this.collapsedGroupingsState.state$.pipe(map((c) => new Set(c))); constructor( - protected organizationService: OrganizationService, + protected organizationService: vNextOrganizationService, protected folderService: FolderService, protected cipherService: CipherService, protected collectionService: CollectionService, protected policyService: PolicyService, protected stateProvider: StateProvider, + private accountService: AccountService, ) {} async storeCollapsedFilterNodes(collapsedFilterNodes: Set): Promise { @@ -50,9 +49,12 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti } async buildOrganizations(): Promise { - let organizations = await this.organizationService.getAll(); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + let organizations = await firstValueFrom(this.organizationService.organizations$(userId)); if (organizations != null) { - organizations = organizations.filter(isMember).sort((a, b) => a.name.localeCompare(b.name)); + organizations = organizations + .filter((o) => o.isMember) + .sort((a, b) => a.name.localeCompare(b.name)); } return organizations; diff --git a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.abstraction.ts similarity index 100% rename from libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts rename to libs/common/src/admin-console/abstractions/organization/vnext.organization.service.abstraction.ts diff --git a/libs/common/src/admin-console/services/organization/default-vnext-organization.service.ts b/libs/common/src/admin-console/services/organization/default-vnext-organization.service.ts index 8b73c271daf..e1956b864d3 100644 --- a/libs/common/src/admin-console/services/organization/default-vnext-organization.service.ts +++ b/libs/common/src/admin-console/services/organization/default-vnext-organization.service.ts @@ -4,7 +4,7 @@ import { map, Observable } from "rxjs"; import { StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; -import { vNextInternalOrganizationServiceAbstraction } from "../../abstractions/organization/vnext.organization.service"; +import { vNextInternalOrganizationServiceAbstraction } from "../../abstractions/organization/vnext.organization.service.abstraction"; import { OrganizationData } from "../../models/data/organization.data"; import { Organization } from "../../models/domain/organization"; diff --git a/libs/common/src/admin-console/services/policy/policy.service.spec.ts b/libs/common/src/admin-console/services/policy/policy.service.spec.ts index d9802db9e38..e946093ca82 100644 --- a/libs/common/src/admin-console/services/policy/policy.service.spec.ts +++ b/libs/common/src/admin-console/services/policy/policy.service.spec.ts @@ -3,7 +3,6 @@ import { firstValueFrom, of } from "rxjs"; import { FakeStateProvider, mockAccountServiceWith } from "../../../../spec"; import { FakeActiveUserState } from "../../../../spec/fake-state"; -import { OrganizationService } from "../../../admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserStatusType, OrganizationUserType, @@ -18,11 +17,12 @@ import { Policy } from "../../../admin-console/models/domain/policy"; import { ResetPasswordPolicyOptions } from "../../../admin-console/models/domain/reset-password-policy-options"; import { POLICIES, PolicyService } from "../../../admin-console/services/policy/policy.service"; import { PolicyId, UserId } from "../../../types/guid"; +import { vNextOrganizationService } from "../../abstractions/organization/vnext.organization.service.abstraction"; describe("PolicyService", () => { const userId = "userId" as UserId; let stateProvider: FakeStateProvider; - let organizationService: MockProxy; + let organizationService: MockProxy; let activeUserState: FakeActiveUserState>; let policyService: PolicyService; @@ -30,7 +30,7 @@ describe("PolicyService", () => { beforeEach(() => { const accountService = mockAccountServiceWith(userId); stateProvider = new FakeStateProvider(accountService); - organizationService = mock(); + organizationService = mock(); activeUserState = stateProvider.activeUser.getFake(POLICIES); @@ -56,9 +56,7 @@ describe("PolicyService", () => { organization("org6", true, true, OrganizationUserStatusType.Confirmed, true), ]); - organizationService.organizations$ = organizations$; - - organizationService.getAll$.mockReturnValue(organizations$); + organizationService.organizations$.mockReturnValue(organizations$); policyService = new PolicyService(stateProvider, organizationService); }); @@ -196,7 +194,7 @@ describe("PolicyService", () => { describe("getResetPasswordPolicyOptions", () => { it("default", async () => { - const result = policyService.getResetPasswordPolicyOptions(null, null); + const result = policyService.getResetPasswordPolicyOptions([], ""); expect(result).toEqual([new ResetPasswordPolicyOptions(), false]); }); diff --git a/libs/common/src/admin-console/services/policy/policy.service.ts b/libs/common/src/admin-console/services/policy/policy.service.ts index 7a04ba38aa7..26544a4be07 100644 --- a/libs/common/src/admin-console/services/policy/policy.service.ts +++ b/libs/common/src/admin-console/services/policy/policy.service.ts @@ -1,10 +1,10 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { combineLatest, firstValueFrom, map, Observable, of } from "rxjs"; +import { combineLatest, firstValueFrom, map, Observable, of, switchMap } from "rxjs"; import { UserKeyDefinition, POLICIES_DISK, StateProvider } from "../../../platform/state"; import { PolicyId, UserId } from "../../../types/guid"; -import { OrganizationService } from "../../abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "../../abstractions/organization/vnext.organization.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "../../abstractions/policy/policy.service.abstraction"; import { OrganizationUserStatusType, PolicyType } from "../../enums"; import { PolicyData } from "../../models/data/policy.data"; @@ -31,7 +31,7 @@ export class PolicyService implements InternalPolicyServiceAbstraction { constructor( private stateProvider: StateProvider, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, ) {} get$(policyType: PolicyType): Observable { @@ -39,7 +39,11 @@ export class PolicyService implements InternalPolicyServiceAbstraction { map((policies) => policies.filter((p) => p.type === policyType)), ); - return combineLatest([filteredPolicies$, this.organizationService.organizations$]).pipe( + const organizations$ = this.stateProvider.activeUserId$.pipe( + switchMap((userId) => this.organizationService.organizations$(userId)), + ); + + return combineLatest([filteredPolicies$, organizations$]).pipe( map( ([policies, organizations]) => this.enforcedPolicyFilter(policies, organizations)?.at(0) ?? null, @@ -53,7 +57,7 @@ export class PolicyService implements InternalPolicyServiceAbstraction { map((policies) => policies.filter((p) => p.type === policyType)), ); - return combineLatest([filteredPolicies$, this.organizationService.getAll$(userId)]).pipe( + return combineLatest([filteredPolicies$, this.organizationService.organizations$(userId)]).pipe( map(([policies, organizations]) => this.enforcedPolicyFilter(policies, organizations)), ); } diff --git a/libs/common/src/auth/services/key-connector.service.spec.ts b/libs/common/src/auth/services/key-connector.service.spec.ts index b1bf87693c1..9038f81612f 100644 --- a/libs/common/src/auth/services/key-connector.service.spec.ts +++ b/libs/common/src/auth/services/key-connector.service.spec.ts @@ -1,9 +1,11 @@ import { mock } from "jest-mock-extended"; +import { of } from "rxjs"; + +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { KeyService } from "../../../../key-management/src/abstractions/key.service"; import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../spec"; import { ApiService } from "../../abstractions/api.service"; -import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationData } from "../../admin-console/models/data/organization.data"; import { Organization } from "../../admin-console/models/domain/organization"; import { ProfileOrganizationResponse } from "../../admin-console/models/response/profile-organization.response"; @@ -31,7 +33,7 @@ describe("KeyConnectorService", () => { const apiService = mock(); const tokenService = mock(); const logService = mock(); - const organizationService = mock(); + const organizationService = mock(); const keyGenerationService = mock(); let stateProvider: FakeStateProvider; @@ -93,7 +95,7 @@ describe("KeyConnectorService", () => { organizationData(true, false, "https://key-connector-url.com", 2, false), organizationData(true, true, "https://other-url.com", 2, false), ]; - organizationService.getAll.mockResolvedValue(orgs); + organizationService.organizations$.mockReturnValue(of(orgs)); // Act const result = await keyConnectorService.getManagingOrganization(); @@ -108,7 +110,7 @@ describe("KeyConnectorService", () => { organizationData(true, false, "https://key-connector-url.com", 2, false), organizationData(false, false, "https://key-connector-url.com", 2, false), ]; - organizationService.getAll.mockResolvedValue(orgs); + organizationService.organizations$.mockReturnValue(of(orgs)); // Act const result = await keyConnectorService.getManagingOrganization(); @@ -123,7 +125,7 @@ describe("KeyConnectorService", () => { organizationData(true, true, "https://key-connector-url.com", 0, false), organizationData(true, true, "https://key-connector-url.com", 1, false), ]; - organizationService.getAll.mockResolvedValue(orgs); + organizationService.organizations$.mockReturnValue(of(orgs)); // Act const result = await keyConnectorService.getManagingOrganization(); @@ -138,7 +140,7 @@ describe("KeyConnectorService", () => { organizationData(true, true, "https://key-connector-url.com", 2, true), organizationData(false, true, "https://key-connector-url.com", 2, true), ]; - organizationService.getAll.mockResolvedValue(orgs); + organizationService.organizations$.mockReturnValue(of(orgs)); // Act const result = await keyConnectorService.getManagingOrganization(); @@ -179,7 +181,7 @@ describe("KeyConnectorService", () => { // create organization object const data = organizationData(true, true, "https://key-connector-url.com", 2, false); - organizationService.getAll.mockResolvedValue([data]); + organizationService.organizations$.mockReturnValue(of([data])); // uses KeyConnector const state = stateProvider.activeUser.getFake(USES_KEY_CONNECTOR); @@ -193,7 +195,7 @@ describe("KeyConnectorService", () => { it("should return false if the user does not need migration", async () => { tokenService.getIsExternal.mockResolvedValue(false); const data = organizationData(false, false, "https://key-connector-url.com", 2, false); - organizationService.getAll.mockResolvedValue([data]); + organizationService.organizations$.mockReturnValue(of([data])); const state = stateProvider.activeUser.getFake(USES_KEY_CONNECTOR); state.nextState(true); @@ -273,7 +275,7 @@ describe("KeyConnectorService", () => { const masterKey = getMockMasterKey(); const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64); const error = new Error("Failed to post user key to key connector"); - organizationService.getAll.mockResolvedValue([organization]); + organizationService.organizations$.mockReturnValue(of([organization])); masterPasswordService.masterKeySubject.next(masterKey); jest.spyOn(keyConnectorService, "getManagingOrganization").mockResolvedValue(organization); diff --git a/libs/common/src/auth/services/key-connector.service.ts b/libs/common/src/auth/services/key-connector.service.ts index f798413162e..57761179dbd 100644 --- a/libs/common/src/auth/services/key-connector.service.ts +++ b/libs/common/src/auth/services/key-connector.service.ts @@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs"; import { LogoutReason } from "@bitwarden/auth/common"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { Argon2KdfConfig, KdfConfig, @@ -12,7 +13,6 @@ import { } from "@bitwarden/key-management"; import { ApiService } from "../../abstractions/api.service"; -import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserType } from "../../admin-console/enums"; import { Organization } from "../../admin-console/models/domain/organization"; import { KeysRequest } from "../../models/request/keys.request"; @@ -64,7 +64,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction { private apiService: ApiService, private tokenService: TokenService, private logService: LogService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private keyGenerationService: KeyGenerationService, private logoutCallback: (logoutReason: LogoutReason, userId?: string) => Promise, private stateProvider: StateProvider, @@ -122,7 +122,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction { } async getManagingOrganization(userId?: UserId): Promise { - const orgs = await this.organizationService.getAll(userId); + const orgs = await firstValueFrom(this.organizationService.organizations$(userId)); return orgs.find( (o) => o.keyConnectorEnabled && diff --git a/libs/common/src/platform/sync/default-sync.service.ts b/libs/common/src/platform/sync/default-sync.service.ts index 9e36aa69417..b087e20939b 100644 --- a/libs/common/src/platform/sync/default-sync.service.ts +++ b/libs/common/src/platform/sync/default-sync.service.ts @@ -8,11 +8,11 @@ import { CollectionDetailsResponse, } from "@bitwarden/admin-console/common"; +import { vNextInternalOrganizationServiceAbstraction } from "../..//admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { UserDecryptionOptionsServiceAbstraction } from "../../../../auth/src/common/abstractions"; import { LogoutReason } from "../../../../auth/src/common/types"; import { KeyService } from "../../../../key-management/src/abstractions/key.service"; import { ApiService } from "../../abstractions/api.service"; -import { InternalOrganizationServiceAbstraction } from "../../admin-console/abstractions/organization/organization.service.abstraction"; import { InternalPolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderService } from "../../admin-console/abstractions/provider.service"; import { OrganizationUserType } from "../../admin-console/enums"; @@ -72,7 +72,7 @@ export class DefaultSyncService extends CoreSyncService { stateService: StateService, private providerService: ProviderService, folderApiService: FolderApiServiceAbstraction, - private organizationService: InternalOrganizationServiceAbstraction, + private organizationService: vNextInternalOrganizationServiceAbstraction, sendApiService: SendApiService, private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, private avatarService: AvatarService, diff --git a/libs/common/src/services/event/event-collection.service.ts b/libs/common/src/services/event/event-collection.service.ts index b06985e0ba7..7c00387131a 100644 --- a/libs/common/src/services/event/event-collection.service.ts +++ b/libs/common/src/services/event/event-collection.service.ts @@ -1,10 +1,12 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { firstValueFrom, map, from, zip, Observable } from "rxjs"; +import { firstValueFrom, map, from, zip } from "rxjs"; + +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { EventCollectionService as EventCollectionServiceAbstraction } from "../../abstractions/event/event-collection.service"; import { EventUploadService } from "../../abstractions/event/event-upload.service"; -import { OrganizationService } from "../../admin-console/abstractions/organization/organization.service.abstraction"; import { AccountService } from "../../auth/abstractions/account.service"; import { AuthService } from "../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../auth/enums/authentication-status"; @@ -17,20 +19,18 @@ import { CipherView } from "../../vault/models/view/cipher.view"; import { EVENT_COLLECTION } from "./key-definitions"; export class EventCollectionService implements EventCollectionServiceAbstraction { - private orgIds$: Observable; - constructor( private cipherService: CipherService, private stateProvider: StateProvider, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, private eventUploadService: EventUploadService, private authService: AuthService, private accountService: AccountService, - ) { - this.orgIds$ = this.organizationService.organizations$.pipe( - map((orgs) => orgs?.filter((o) => o.useEvents)?.map((x) => x.id) ?? []), - ); - } + ) {} + + private getOrgIds = (orgs: Organization[]): string[] => { + return orgs?.filter((o) => o.useEvents)?.map((x) => x.id) ?? []; + }; /** Adds an event to the active user's event collection * @param eventType the event type to be added @@ -49,7 +49,8 @@ export class EventCollectionService implements EventCollectionServiceAbstraction return; } - const events$ = this.orgIds$.pipe( + const events$ = this.organizationService.organizations$(userId).pipe( + map((orgs) => this.getOrgIds(orgs)), map((orgs) => ciphers .filter((c) => orgs.includes(c.organizationId)) @@ -122,8 +123,13 @@ export class EventCollectionService implements EventCollectionServiceAbstraction ): Promise { const cipher$ = from(this.cipherService.get(cipherId)); + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + const orgIds$ = this.organizationService + .organizations$(userId) + .pipe(map((orgs) => this.getOrgIds(orgs))); + const [authStatus, orgIds, cipher] = await firstValueFrom( - zip(this.authService.activeAccountStatus$, this.orgIds$, cipher$), + zip(this.authService.activeAccountStatus$, orgIds$, cipher$), ); // The user must be authorized diff --git a/libs/common/src/vault/services/cipher-authorization.service.spec.ts b/libs/common/src/vault/services/cipher-authorization.service.spec.ts index cccd29ad697..192fccae9d0 100644 --- a/libs/common/src/vault/services/cipher-authorization.service.spec.ts +++ b/libs/common/src/vault/services/cipher-authorization.service.spec.ts @@ -1,11 +1,13 @@ import { mock } from "jest-mock-extended"; -import { firstValueFrom, of } from "rxjs"; +import { Observable, firstValueFrom, of } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionId } from "@bitwarden/common/types/guid"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { CollectionId, UserId } from "@bitwarden/common/types/guid"; +import { FakeAccountService, mockAccountServiceWith } from "../../../spec"; import { CipherView } from "../models/view/cipher.view"; import { @@ -17,7 +19,9 @@ describe("CipherAuthorizationService", () => { let cipherAuthorizationService: CipherAuthorizationService; const mockCollectionService = mock(); - const mockOrganizationService = mock(); + const mockOrganizationService = mock(); + const mockUserId = Utils.newGuid() as UserId; + let mockAccountService: FakeAccountService; // Mock factories const createMockCipher = ( @@ -42,6 +46,7 @@ describe("CipherAuthorizationService", () => { isAdmin = false, editAnyCollection = false, } = {}) => ({ + id: "org1", allowAdminAccessToAllCollectionItems, canEditAllCiphers, canEditUnassignedCiphers, @@ -53,9 +58,11 @@ describe("CipherAuthorizationService", () => { beforeEach(() => { jest.clearAllMocks(); + mockAccountService = mockAccountServiceWith(mockUserId); cipherAuthorizationService = new DefaultCipherAuthorizationService( mockCollectionService, mockOrganizationService, + mockAccountService, ); }); @@ -72,7 +79,9 @@ describe("CipherAuthorizationService", () => { it("should return true if isAdminConsoleAction is true and cipher is unassigned", (done) => { const cipher = createMockCipher("org1", []) as CipherView; const organization = createMockOrganization({ canEditUnassignedCiphers: true }); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization]) as Observable, + ); cipherAuthorizationService.canDeleteCipher$(cipher, [], true).subscribe((result) => { expect(result).toBe(true); @@ -83,11 +92,13 @@ describe("CipherAuthorizationService", () => { it("should return true if isAdminConsoleAction is true and user can edit all ciphers in the org", (done) => { const cipher = createMockCipher("org1", ["col1"]) as CipherView; const organization = createMockOrganization({ canEditAllCiphers: true }); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization]) as Observable, + ); cipherAuthorizationService.canDeleteCipher$(cipher, [], true).subscribe((result) => { expect(result).toBe(true); - expect(mockOrganizationService.get$).toHaveBeenCalledWith("org1"); + expect(mockOrganizationService.organizations$).toHaveBeenCalledWith(mockUserId); done(); }); }); @@ -95,7 +106,7 @@ describe("CipherAuthorizationService", () => { it("should return false if isAdminConsoleAction is true but user does not have permission to edit unassigned ciphers", (done) => { const cipher = createMockCipher("org1", []) as CipherView; const organization = createMockOrganization({ canEditUnassignedCiphers: false }); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue(of([organization] as Organization[])); cipherAuthorizationService.canDeleteCipher$(cipher, [], true).subscribe((result) => { expect(result).toBe(false); @@ -106,8 +117,8 @@ describe("CipherAuthorizationService", () => { it("should return true if activeCollectionId is provided and has manage permission", (done) => { const cipher = createMockCipher("org1", ["col1", "col2"]) as CipherView; const activeCollectionId = "col1" as CollectionId; - const org = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(org as Organization)); + const organization = createMockOrganization(); + mockOrganizationService.organizations$.mockReturnValue(of([organization] as Organization[])); const allCollections = [ createMockCollection("col1", true), @@ -132,8 +143,8 @@ describe("CipherAuthorizationService", () => { it("should return false if activeCollectionId is provided and manage permission is not present", (done) => { const cipher = createMockCipher("org1", ["col1", "col2"]) as CipherView; const activeCollectionId = "col1" as CollectionId; - const org = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(org as Organization)); + const organization = createMockOrganization(); + mockOrganizationService.organizations$.mockReturnValue(of([organization] as Organization[])); const allCollections = [ createMockCollection("col1", false), @@ -157,8 +168,8 @@ describe("CipherAuthorizationService", () => { it("should return true if any collection has manage permission", (done) => { const cipher = createMockCipher("org1", ["col1", "col2", "col3"]) as CipherView; - const org = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(org as Organization)); + const organization = createMockOrganization(); + mockOrganizationService.organizations$.mockReturnValue(of([organization] as Organization[])); const allCollections = [ createMockCollection("col1", false), @@ -182,8 +193,8 @@ describe("CipherAuthorizationService", () => { it("should return false if no collection has manage permission", (done) => { const cipher = createMockCipher("org1", ["col1", "col2"]) as CipherView; - const org = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(org as Organization)); + const organization = createMockOrganization(); + mockOrganizationService.organizations$.mockReturnValue(of([organization] as Organization[])); const allCollections = [ createMockCollection("col1", false), @@ -216,7 +227,9 @@ describe("CipherAuthorizationService", () => { it("should return true for admin users", async () => { const cipher = createMockCipher("org1", []) as CipherView; const organization = createMockOrganization({ isAdmin: true }); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization] as Organization[]), + ); const result = await firstValueFrom( cipherAuthorizationService.canCloneCipher$(cipher, true), @@ -227,7 +240,9 @@ describe("CipherAuthorizationService", () => { it("should return true for custom user with canEditAnyCollection", async () => { const cipher = createMockCipher("org1", []) as CipherView; const organization = createMockOrganization({ editAnyCollection: true }); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization] as Organization[]), + ); const result = await firstValueFrom( cipherAuthorizationService.canCloneCipher$(cipher, true), @@ -240,7 +255,9 @@ describe("CipherAuthorizationService", () => { it("should return true if at least one cipher collection has manage permission", async () => { const cipher = createMockCipher("org1", ["col1", "col2"]) as CipherView; const organization = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization] as Organization[]), + ); const allCollections = [ createMockCollection("col1", true), @@ -257,7 +274,9 @@ describe("CipherAuthorizationService", () => { it("should return false if no collection has manage permission", async () => { const cipher = createMockCipher("org1", ["col1", "col2"]) as CipherView; const organization = createMockOrganization(); - mockOrganizationService.get$.mockReturnValue(of(organization as Organization)); + mockOrganizationService.organizations$.mockReturnValue( + of([organization] as Organization[]), + ); const allCollections = [ createMockCollection("col1", false), diff --git a/libs/common/src/vault/services/cipher-authorization.service.ts b/libs/common/src/vault/services/cipher-authorization.service.ts index 260d1eeece7..8d8a3b598bb 100644 --- a/libs/common/src/vault/services/cipher-authorization.service.ts +++ b/libs/common/src/vault/services/cipher-authorization.service.ts @@ -3,7 +3,8 @@ import { map, Observable, of, shareReplay, switchMap } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { CollectionId } from "@bitwarden/common/types/guid"; import { Cipher } from "../models/domain/cipher"; @@ -50,9 +51,15 @@ export abstract class CipherAuthorizationService { export class DefaultCipherAuthorizationService implements CipherAuthorizationService { constructor( private collectionService: CollectionService, - private organizationService: OrganizationService, + private organizationService: vNextOrganizationService, + private accountService: AccountService, ) {} + private organization$ = (cipher: CipherLike) => + this.accountService.activeAccount$.pipe( + switchMap((account) => this.organizationService.organizations$(account?.id)), + map((orgs) => orgs.find((org) => org.id === cipher.organizationId)), + ); /** * * {@link CipherAuthorizationService.canDeleteCipher$} @@ -66,7 +73,7 @@ export class DefaultCipherAuthorizationService implements CipherAuthorizationSer return of(true); } - return this.organizationService.get$(cipher.organizationId).pipe( + return this.organization$(cipher).pipe( switchMap((organization) => { if (isAdminConsoleAction) { // If the user is an admin, they can delete an unassigned cipher @@ -104,7 +111,7 @@ export class DefaultCipherAuthorizationService implements CipherAuthorizationSer return of(true); } - return this.organizationService.get$(cipher.organizationId).pipe( + return this.organization$(cipher).pipe( switchMap((organization) => { // Admins and custom users can always clone when in the Admin Console if (