mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
[PM-24096] replace getOrgKey with orgKey$, refactor collectionAdminService (#15928)
* replace getOrgKey with orgKey$, refactor collectionAdminService * clean up * uncomment accidental commet * remove cache
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { firstValueFrom, switchMap } from "rxjs";
|
||||
|
||||
import {
|
||||
CollectionAdminService,
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@@ -99,6 +101,7 @@ export class VaultHeaderComponent {
|
||||
private dialogService: DialogService,
|
||||
private collectionAdminService: CollectionAdminService,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
get title() {
|
||||
@@ -199,7 +202,14 @@ export class VaultHeaderComponent {
|
||||
|
||||
async addCollection() {
|
||||
if (this.organization.productTierType === ProductTierType.Free) {
|
||||
const collections = await this.collectionAdminService.getAll(this.organization.id);
|
||||
const collections = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.collectionAdminService.collectionAdminViews$(this.organization.id, userId),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (collections.length === this.organization.maxCollections) {
|
||||
this.showFreeOrgUpgradeDialog();
|
||||
return;
|
||||
|
||||
@@ -363,7 +363,12 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.allCollectionsWithoutUnassigned$ = this.refresh$.pipe(
|
||||
switchMap(() => organizationId$),
|
||||
switchMap((orgId) => this.collectionAdminService.getAll(orgId)),
|
||||
switchMap((orgId) =>
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.collectionAdminService.collectionAdminViews$(orgId, userId)),
|
||||
),
|
||||
),
|
||||
shareReplay({ refCount: false, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -156,7 +157,11 @@ export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
private orgCollections$ = from(this.collectionAdminService.getAll(this.organizationId)).pipe(
|
||||
private orgCollections$ = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.collectionAdminService.collectionAdminViews$(this.organizationId, userId),
|
||||
),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -276,9 +277,16 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
),
|
||||
);
|
||||
|
||||
const collections = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.collectionAdminService.collectionAdminViews$(this.params.organizationId, userId),
|
||||
),
|
||||
);
|
||||
|
||||
combineLatest({
|
||||
organization: this.organization$,
|
||||
collections: this.collectionAdminService.getAll(this.params.organizationId),
|
||||
collections,
|
||||
userDetails: userDetails$,
|
||||
groups: groups$,
|
||||
})
|
||||
|
||||
@@ -200,7 +200,14 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
this.organization.canManageUsersPassword &&
|
||||
!this.organization.hasPublicAndPrivateKeys
|
||||
) {
|
||||
const orgShareKey = await this.keyService.getOrgKey(this.organization.id);
|
||||
const orgShareKey = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.keyService.orgKeys$(userId)),
|
||||
map((orgKeys) => orgKeys[this.organization.id] ?? null),
|
||||
),
|
||||
);
|
||||
|
||||
const orgKeys = await this.keyService.makeKeyPair(orgShareKey);
|
||||
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
const response = await this.organizationApiService.updateKeys(
|
||||
@@ -353,7 +360,13 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
this.organizationUserService.confirmUser(this.organization, user, publicKey),
|
||||
);
|
||||
} else {
|
||||
const orgKey = await this.keyService.getOrgKey(this.organization.id);
|
||||
const orgKey = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.keyService.orgKeys$(userId)),
|
||||
map((orgKeys) => orgKeys[this.organization.id] ?? null),
|
||||
),
|
||||
);
|
||||
const key = await this.encryptService.encapsulateKeyUnsigned(orgKey, publicKey);
|
||||
const request = new OrganizationUserConfirmRequest();
|
||||
request.key = key.encryptedString;
|
||||
|
||||
@@ -17,8 +17,9 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { EncryptionType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { UserKey, OrgKey, MasterKey } from "@bitwarden/common/types/key";
|
||||
import { KdfType, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
@@ -36,6 +37,8 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
|
||||
let organizationApiService: MockProxy<OrganizationApiService>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
let accountService: FakeAccountService;
|
||||
|
||||
beforeAll(() => {
|
||||
keyService = mock<KeyService>();
|
||||
@@ -44,6 +47,7 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
organizationUserApiService = mock<OrganizationUserApiService>();
|
||||
organizationApiService = mock<OrganizationApiService>();
|
||||
i18nService = mock<I18nService>();
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
|
||||
sut = new OrganizationUserResetPasswordService(
|
||||
keyService,
|
||||
@@ -52,6 +56,7 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
organizationUserApiService,
|
||||
organizationApiService,
|
||||
i18nService,
|
||||
accountService,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -142,7 +147,10 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
|
||||
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
|
||||
const mockOrgKey = new SymmetricCryptoKey(mockRandomBytes) as OrgKey;
|
||||
keyService.getOrgKey.mockResolvedValue(mockOrgKey);
|
||||
keyService.orgKeys$.mockReturnValue(
|
||||
of({ [mockOrgId]: mockOrgKey } as Record<OrganizationId, OrgKey>),
|
||||
);
|
||||
|
||||
encryptService.decryptToBytes.mockResolvedValue(mockRandomBytes);
|
||||
|
||||
encryptService.rsaDecrypt.mockResolvedValue(mockRandomBytes);
|
||||
@@ -170,7 +178,7 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
});
|
||||
|
||||
it("should throw an error if the org key is null", async () => {
|
||||
keyService.getOrgKey.mockResolvedValue(null);
|
||||
keyService.orgKeys$.mockReturnValue(of(null));
|
||||
await expect(
|
||||
sut.resetMasterPassword(mockNewMP, mockEmail, mockOrgUserId, mockOrgId),
|
||||
).rejects.toThrow();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Injectable } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { firstValueFrom, map, switchMap } from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import {
|
||||
EncryptedString,
|
||||
@@ -47,6 +49,7 @@ export class OrganizationUserResetPasswordService
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private i18nService: I18nService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -111,7 +114,14 @@ export class OrganizationUserResetPasswordService
|
||||
}
|
||||
|
||||
// Decrypt Organization's encrypted Private Key with org key
|
||||
const orgSymKey = await this.keyService.getOrgKey(orgId);
|
||||
const orgSymKey = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.keyService.orgKeys$(userId)),
|
||||
map((orgKeys) => orgKeys[orgId as OrganizationId] ?? null),
|
||||
),
|
||||
);
|
||||
|
||||
if (orgSymKey == null) {
|
||||
throw new Error("No org key found");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
firstValueFrom,
|
||||
from,
|
||||
lastValueFrom,
|
||||
map,
|
||||
of,
|
||||
Subject,
|
||||
switchMap,
|
||||
@@ -28,6 +29,7 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
@@ -179,7 +181,13 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Backfill pub/priv key if necessary
|
||||
if (!this.org.hasPublicAndPrivateKeys) {
|
||||
const orgShareKey = await this.keyService.getOrgKey(this.organizationId);
|
||||
const orgShareKey = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.keyService.orgKeys$(userId)),
|
||||
map((orgKeys) => orgKeys[this.organizationId as OrganizationId] ?? null),
|
||||
),
|
||||
);
|
||||
const orgKeys = await this.keyService.makeKeyPair(orgShareKey);
|
||||
request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
}
|
||||
|
||||
@@ -240,9 +240,15 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
return this.groupService.getAll(orgId);
|
||||
}),
|
||||
);
|
||||
|
||||
const collections = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.collectionAdminService.collectionAdminViews$(orgId, userId)),
|
||||
);
|
||||
|
||||
combineLatest({
|
||||
organization: organization$,
|
||||
collections: this.collectionAdminService.getAll(orgId),
|
||||
collections,
|
||||
groups: groups$,
|
||||
users: this.organizationUserApiService.getAllMiniUserDetails(orgId),
|
||||
})
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionAdminService, CollectionAdminView } from "@bitwarden/admin-console/common";
|
||||
import { ImportCollectionServiceAbstraction } from "@bitwarden/importer-core";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
|
||||
@Injectable()
|
||||
export class ImportCollectionAdminService implements ImportCollectionServiceAbstraction {
|
||||
constructor(private collectionAdminService: CollectionAdminService) {}
|
||||
|
||||
async getAllAdminCollections(organizationId: string): Promise<CollectionAdminView[]> {
|
||||
return await this.collectionAdminService.getAll(organizationId);
|
||||
async getAllAdminCollections(
|
||||
organizationId: string,
|
||||
userId: UserId,
|
||||
): Promise<CollectionAdminView[]> {
|
||||
return await firstValueFrom(
|
||||
this.collectionAdminService.collectionAdminViews$(organizationId, userId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { firstValueFrom, switchMap } from "rxjs";
|
||||
|
||||
import {
|
||||
Unassigned,
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@@ -93,6 +95,7 @@ export class VaultHeaderComponent {
|
||||
private dialogService: DialogService,
|
||||
private router: Router,
|
||||
private configService: ConfigService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -225,7 +228,14 @@ export class VaultHeaderComponent {
|
||||
);
|
||||
|
||||
if (this.organizations?.length == 1 && !!organization) {
|
||||
const collections = await this.collectionAdminService.getAll(organization.id);
|
||||
const collections = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.collectionAdminService.collectionAdminViews$(organization.id, userId),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (collections.length === organization.maxCollections) {
|
||||
await this.showFreeOrgUpgradeDialog(organization);
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TestBed } from "@angular/core/testing";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { CollectionAdminService, CollectionAdminView } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -71,7 +71,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
{ provide: OrganizationService, useValue: { organizations$: () => orgs$ } },
|
||||
{
|
||||
provide: CollectionAdminService,
|
||||
useValue: { getAll: () => Promise.resolve([collection, collection2]) },
|
||||
useValue: { collectionAdminViews$: () => of([collection, collection2]) },
|
||||
},
|
||||
{
|
||||
provide: PolicyService,
|
||||
|
||||
@@ -31,8 +31,9 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
private apiService: ApiService = inject(ApiService);
|
||||
private accountService: AccountService = inject(AccountService);
|
||||
|
||||
private organizationDataOwnershipDisabled$ = this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
private userId$ = this.accountService.activeAccount$.pipe(getUserId);
|
||||
|
||||
private organizationDataOwnershipDisabled$ = this.userId$.pipe(
|
||||
switchMap((userId) =>
|
||||
this.policyService.policyAppliesToUser$(PolicyType.OrganizationDataOwnership, userId),
|
||||
),
|
||||
@@ -44,9 +45,9 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
filter((filter) => filter !== undefined),
|
||||
);
|
||||
|
||||
private allOrganizations$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService.organizations$(account?.id).pipe(
|
||||
private allOrganizations$ = this.userId$.pipe(
|
||||
switchMap((userId) =>
|
||||
this.organizationService.organizations$(userId).pipe(
|
||||
map((orgs) => {
|
||||
return orgs.filter(
|
||||
(o) => o.isMember && o.enabled && o.status === OrganizationUserStatusType.Confirmed,
|
||||
@@ -60,8 +61,8 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
map(([orgs, orgId]) => orgs.find((o) => o.id === orgId)),
|
||||
);
|
||||
|
||||
private allCollections$ = this.organization$.pipe(
|
||||
switchMap(async (org) => await this.collectionAdminService.getAll(org.id)),
|
||||
private allCollections$ = combineLatest([this.organization$, this.userId$]).pipe(
|
||||
switchMap(([org, userId]) => this.collectionAdminService.collectionAdminViews$(org.id, userId)),
|
||||
);
|
||||
|
||||
async buildConfig(
|
||||
|
||||
Reference in New Issue
Block a user