|
|
|
|
@ -1,11 +1,14 @@
|
|
|
|
|
// FIXME: Update this file to be type safe and remove this and next line
|
|
|
|
|
// @ts-strict-ignore
|
|
|
|
|
|
|
|
|
|
import { combineLatest, firstValueFrom, from, map, Observable, of, switchMap } from "rxjs";
|
|
|
|
|
|
|
|
|
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
|
|
|
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
|
|
|
|
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
|
|
|
|
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
|
|
|
|
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
|
|
|
|
|
import { CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
|
|
|
|
import { OrgKey } from "@bitwarden/common/types/key";
|
|
|
|
|
import { KeyService } from "@bitwarden/key-management";
|
|
|
|
|
|
|
|
|
|
import { CollectionAdminService, CollectionService } from "../abstractions";
|
|
|
|
|
@ -28,37 +31,23 @@ export class DefaultCollectionAdminService implements CollectionAdminService {
|
|
|
|
|
private collectionService: CollectionService,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
async getAll(organizationId: string): Promise<CollectionAdminView[]> {
|
|
|
|
|
const collectionResponse =
|
|
|
|
|
await this.apiService.getManyCollectionsWithAccessDetails(organizationId);
|
|
|
|
|
|
|
|
|
|
if (collectionResponse?.data == null || collectionResponse.data.length === 0) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await this.decryptMany(organizationId, collectionResponse.data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async get(
|
|
|
|
|
organizationId: string,
|
|
|
|
|
collectionId: string,
|
|
|
|
|
): Promise<CollectionAdminView | undefined> {
|
|
|
|
|
const collectionResponse = await this.apiService.getCollectionAccessDetails(
|
|
|
|
|
organizationId,
|
|
|
|
|
collectionId,
|
|
|
|
|
collectionAdminViews$(organizationId: string, userId: UserId): Observable<CollectionAdminView[]> {
|
|
|
|
|
return combineLatest([
|
|
|
|
|
this.keyService.orgKeys$(userId),
|
|
|
|
|
from(this.apiService.getManyCollectionsWithAccessDetails(organizationId)),
|
|
|
|
|
]).pipe(
|
|
|
|
|
switchMap(([orgKey, res]) => {
|
|
|
|
|
if (res?.data == null || res.data.length === 0) {
|
|
|
|
|
return of([]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.decryptMany(organizationId, res.data, orgKey);
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (collectionResponse == null) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const [view] = await this.decryptMany(organizationId, [collectionResponse]);
|
|
|
|
|
|
|
|
|
|
return view;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async save(collection: CollectionAdminView, userId: UserId): Promise<CollectionDetailsResponse> {
|
|
|
|
|
const request = await this.encrypt(collection);
|
|
|
|
|
const request = await this.encrypt(collection, userId);
|
|
|
|
|
|
|
|
|
|
let response: CollectionDetailsResponse;
|
|
|
|
|
if (collection.id == null) {
|
|
|
|
|
@ -112,13 +101,15 @@ export class DefaultCollectionAdminService implements CollectionAdminService {
|
|
|
|
|
private async decryptMany(
|
|
|
|
|
organizationId: string,
|
|
|
|
|
collections: CollectionResponse[] | CollectionAccessDetailsResponse[],
|
|
|
|
|
orgKeys: Record<OrganizationId, OrgKey>,
|
|
|
|
|
): Promise<CollectionAdminView[]> {
|
|
|
|
|
const orgKey = await this.keyService.getOrgKey(organizationId);
|
|
|
|
|
|
|
|
|
|
const promises = collections.map(async (c) => {
|
|
|
|
|
const view = new CollectionAdminView();
|
|
|
|
|
view.id = c.id;
|
|
|
|
|
view.name = await this.encryptService.decryptString(new EncString(c.name), orgKey);
|
|
|
|
|
view.name = await this.encryptService.decryptString(
|
|
|
|
|
new EncString(c.name),
|
|
|
|
|
orgKeys[organizationId as OrganizationId],
|
|
|
|
|
);
|
|
|
|
|
view.externalId = c.externalId;
|
|
|
|
|
view.organizationId = c.organizationId;
|
|
|
|
|
|
|
|
|
|
@ -138,11 +129,15 @@ export class DefaultCollectionAdminService implements CollectionAdminService {
|
|
|
|
|
return await Promise.all(promises);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async encrypt(model: CollectionAdminView): Promise<CollectionRequest> {
|
|
|
|
|
private async encrypt(model: CollectionAdminView, userId: UserId): Promise<CollectionRequest> {
|
|
|
|
|
if (model.organizationId == null) {
|
|
|
|
|
throw new Error("Collection has no organization id.");
|
|
|
|
|
}
|
|
|
|
|
const key = await this.keyService.getOrgKey(model.organizationId);
|
|
|
|
|
const key = await firstValueFrom(
|
|
|
|
|
this.keyService
|
|
|
|
|
.orgKeys$(userId)
|
|
|
|
|
.pipe(map((orgKeys) => orgKeys[model.organizationId] ?? null)),
|
|
|
|
|
);
|
|
|
|
|
if (key == null) {
|
|
|
|
|
throw new Error("No key for this collection's organization.");
|
|
|
|
|
}
|
|
|
|
|
|