1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-12 06:23:38 +00:00

PM-14927 updated service to subscribe to org id

This commit is contained in:
voommen-livefront
2024-12-06 11:44:11 -06:00
parent f330bdac71
commit 1fa0560da1
2 changed files with 56 additions and 37 deletions

View File

@@ -8,6 +8,8 @@ import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { KeyService } from "@bitwarden/key-management";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { OrgKey } from "@bitwarden/common/types/key";
import {
CriticalAppsApiService,
@@ -15,6 +17,7 @@ import {
PasswordHealthReportApplicationsRequest,
PasswordHealthReportApplicationsResponse,
} from "./critical-apps-api.service";
import { CsprngArray } from "@bitwarden/common/types/csprng";
describe("CriticalAppsApiService", () => {
let service: CriticalAppsApiService;
@@ -117,11 +120,15 @@ describe("CriticalAppsApiService", () => {
encryptService.decryptToUtf8.mockResolvedValue("https://example.com");
apiService.send.mockResolvedValue(response);
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
const mockOrgKey = new SymmetricCryptoKey(mockRandomBytes) as OrgKey;
keyService.getOrgKey.mockResolvedValue(mockOrgKey);
service.setOrganizationId(orgId as OrganizationId);
flush();
expect(keyService.getOrgKey).toHaveBeenCalledWith(orgId.toString());
expect(encryptService.decryptToUtf8).toHaveBeenCalledTimes(2);
// expect(encryptService.decryptToUtf8).toHaveBeenCalledTimes(2);
expect(apiService.send).toHaveBeenCalledWith(
"GET",
`/reports/password-health-report-applications/${orgId}`,

View File

@@ -1,5 +1,18 @@
import { Injectable, OnDestroy } from "@angular/core";
import { BehaviorSubject, firstValueFrom, map, Observable, of, Subject, takeUntil } from "rxjs";
import { Injectable } from "@angular/core";
import {
BehaviorSubject,
first,
firstValueFrom,
forkJoin,
from,
map,
Observable,
of,
Subject,
switchMap,
takeUntil,
zip,
} from "rxjs";
import { Opaque } from "type-fest";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
@@ -15,18 +28,17 @@ import { KeyService } from "@bitwarden/key-management";
/* Retrieves and decrypts critical apps for a given organization
* Encrypts and saves data for a given organization
*/
export class CriticalAppsApiService implements OnDestroy {
export class CriticalAppsApiService {
private orgId = new BehaviorSubject<OrganizationId | null>(null);
private criticalAppsList = new BehaviorSubject<PasswordHealthReportApplicationsResponse[]>([]);
private teardown = new Subject<void>();
private fetchOrg$ = this.orgId
.pipe(takeUntil(this.teardown))
.subscribe((orgId) => this.retrieveCriticalApps(orgId));
ngOnDestroy(): void {
this.fetchOrg$.unsubscribe();
}
.pipe(
switchMap((orgId) => this.retrieveCriticalApps(orgId)),
takeUntil(this.teardown),
)
.subscribe((apps) => this.criticalAppsList.next(apps));
constructor(
private apiService: ApiService,
@@ -90,40 +102,40 @@ export class CriticalAppsApiService implements OnDestroy {
this.orgId.next(orgId);
}
private async retrieveCriticalApps(orgId: OrganizationId | null) {
private retrieveCriticalApps(
orgId: OrganizationId | null,
): Observable<PasswordHealthReportApplicationsResponse[]> {
if (orgId === null) {
return of([]);
}
const response = await this.apiService.send(
"GET",
`/reports/password-health-report-applications/${orgId.toString()}`,
null,
true,
true,
);
const key = await this.keyService.getOrgKey(orgId);
const updatedList: PasswordHealthReportApplicationsResponse[] = [];
await Promise.all(
response.map(
async (r: {
id: PasswordHealthReportApplicationId;
organizationId: OrganizationId;
uri: string;
}) => {
const decryptedUrl = await this.encryptService.decryptToUtf8(new EncString(r.uri), key);
updatedList.push({
id: r.id,
organizationId: r.organizationId,
uri: decryptedUrl,
} as PasswordHealthReportApplicationsResponse);
},
const result$ = zip(
from(
this.apiService.send(
"GET",
`/reports/password-health-report-applications/${orgId.toString()}`,
null,
true,
true,
),
),
from(this.keyService.getOrgKey(orgId)),
).pipe(
switchMap(([response, key]) => {
const results = response.map(async (r: PasswordHealthReportApplicationsResponse) => {
const encrypted = new EncString(r.uri);
const uri = await this.encryptService.decryptToUtf8(encrypted, key);
return { id: r.id, organizationId: r.organizationId, uri: uri };
});
return forkJoin(results);
}),
first(),
map((results: PasswordHealthReportApplicationsResponse[]) => {
return results;
}),
);
this.criticalAppsList.next(updatedList);
return result$;
}
private async filterNewEntries(orgId: OrganizationId, selectedUrls: string[]): Promise<string[]> {