mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 19:53:59 +00:00
PM-20578 retrieve report from DB
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
// FIXME: Update this file to be type safe
|
||||
// @ts-strict-ignore
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import {
|
||||
ApplicationHealthReportDetail,
|
||||
ApplicationHealthReportSummary,
|
||||
RiskInsightsReport,
|
||||
GetRiskInsightsReportResponse,
|
||||
} from "../models/password-health";
|
||||
|
||||
export class ReportDecipherService {
|
||||
constructor(
|
||||
private keyService: KeyService,
|
||||
private encryptService: EncryptService,
|
||||
private keyGeneratorService: KeyGenerationService,
|
||||
) {}
|
||||
|
||||
async generateEncryptedRiskInsightsReport(
|
||||
organizationId: OrganizationId,
|
||||
details: ApplicationHealthReportDetail[],
|
||||
summary: ApplicationHealthReportSummary,
|
||||
): Promise<RiskInsightsReport> {
|
||||
const orgKey = await this.keyService.getOrgKey(organizationId as string);
|
||||
if (orgKey === null) {
|
||||
throw new Error("Organization key not found");
|
||||
}
|
||||
|
||||
const reportWithSummary = { details, summary };
|
||||
|
||||
const reportContentEncryptionKey = await this.keyGeneratorService.createKey(512);
|
||||
|
||||
const reportEncrypted = await this.encryptService.encryptString(
|
||||
JSON.stringify(reportWithSummary),
|
||||
reportContentEncryptionKey,
|
||||
);
|
||||
|
||||
const wrappedReportContentEncryptionKey = await this.encryptService.wrapSymmetricKey(
|
||||
reportContentEncryptionKey,
|
||||
orgKey,
|
||||
);
|
||||
|
||||
const reportDataWithWrappedKey = {
|
||||
data: reportEncrypted.encryptedString,
|
||||
key: wrappedReportContentEncryptionKey.encryptedString,
|
||||
};
|
||||
|
||||
const riskInsightReport = {
|
||||
organizationId: organizationId,
|
||||
date: new Date().toISOString(),
|
||||
reportData: JSON.stringify(reportDataWithWrappedKey),
|
||||
totalMembers: 0,
|
||||
totalAtRiskMembers: 0,
|
||||
totalApplications: 0,
|
||||
totalAtRiskApplications: 0,
|
||||
totalCriticalApplications: 0,
|
||||
};
|
||||
|
||||
return riskInsightReport;
|
||||
}
|
||||
|
||||
async decryptRiskInsightsReport(
|
||||
organizationId: OrganizationId,
|
||||
riskInsightsReportResponse: GetRiskInsightsReportResponse,
|
||||
): Promise<[ApplicationHealthReportDetail[], ApplicationHealthReportSummary]> {
|
||||
try {
|
||||
const orgKey = await this.keyService.getOrgKey(organizationId as string);
|
||||
if (orgKey === null) {
|
||||
throw new Error("Organization key not found");
|
||||
}
|
||||
|
||||
const reportDataInJson = JSON.parse(riskInsightsReportResponse.reportData);
|
||||
const reportEncrypted = reportDataInJson.data;
|
||||
const wrappedReportContentEncryptionKey = reportDataInJson.key;
|
||||
|
||||
const unwrappedReportContentEncryptionKey = await this.encryptService.unwrapSymmetricKey(
|
||||
new EncString(wrappedReportContentEncryptionKey),
|
||||
orgKey,
|
||||
);
|
||||
|
||||
const reportUnencrypted = await this.encryptService.decryptString(
|
||||
new EncString(reportEncrypted),
|
||||
unwrappedReportContentEncryptionKey,
|
||||
);
|
||||
|
||||
const reportWithSummary = JSON.parse(reportUnencrypted);
|
||||
const reportJson = reportWithSummary.details;
|
||||
const reportSummary = reportWithSummary.summary;
|
||||
|
||||
return [reportJson, reportSummary];
|
||||
} catch {
|
||||
return [null, null];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { switchMap } from "rxjs/operators";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
import { map, switchMap } from "rxjs/operators";
|
||||
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
DrawerType,
|
||||
} from "../models/password-health";
|
||||
|
||||
import { ReportDecipherService } from "./report-decipher.service";
|
||||
import { RiskInsightsApiService } from "./risk-insights-api.service";
|
||||
import { RiskInsightsReportService } from "./risk-insights-report.service";
|
||||
export class RiskInsightsDataService {
|
||||
@@ -52,6 +52,7 @@ export class RiskInsightsDataService {
|
||||
private reportService: RiskInsightsReportService,
|
||||
private riskInsightsApiService: RiskInsightsApiService,
|
||||
private cipherService: CipherService,
|
||||
private reportDecipherService: ReportDecipherService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -59,38 +60,46 @@ export class RiskInsightsDataService {
|
||||
* @param organizationId The ID of the organization.
|
||||
*/
|
||||
fetchApplicationsReport(organizationId: string, isRefresh?: boolean): void {
|
||||
this.reportService
|
||||
.generateApplicationsReport$(organizationId)
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe({
|
||||
next: (reports: ApplicationHealthReportDetail[]) => {
|
||||
this.applicationsSubject.next(reports);
|
||||
this.errorSubject.next(null);
|
||||
this.appsSummarySubject.next(this.reportService.generateApplicationsSummary(reports));
|
||||
this.dataLastUpdatedSubject.next(new Date());
|
||||
},
|
||||
error: () => {
|
||||
this.applicationsSubject.next([]);
|
||||
},
|
||||
});
|
||||
this.reportService.generateApplicationsReport$(organizationId).subscribe({
|
||||
next: (reports: ApplicationHealthReportDetail[]) => {
|
||||
this.applicationsSubject.next(reports);
|
||||
this.errorSubject.next(null);
|
||||
this.appsSummarySubject.next(this.reportService.generateApplicationsSummary(reports));
|
||||
this.dataLastUpdatedSubject.next(new Date());
|
||||
},
|
||||
error: () => {
|
||||
this.applicationsSubject.next([]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fetchApplicationsReportFromCache(organizationId: string) {
|
||||
fetchApplicationsReportFromCache(organizationId: string, isRefresh: boolean = false) {
|
||||
return this.riskInsightsApiService
|
||||
.getRiskInsightsReport(organizationId as OrganizationId)
|
||||
.pipe(
|
||||
map((reportFromArchive) => {
|
||||
if (isRefresh) {
|
||||
// we force a refresh if isRefresh is true
|
||||
// ignore all data from the server
|
||||
return null;
|
||||
}
|
||||
return reportFromArchive;
|
||||
}),
|
||||
switchMap(async (reportFromArchive) => {
|
||||
if (!reportFromArchive || !reportFromArchive?.date) {
|
||||
this.fetchApplicationsReport(organizationId);
|
||||
const report = await firstValueFrom(
|
||||
this.reportService.generateApplicationsReport$(organizationId),
|
||||
);
|
||||
const summary = this.reportService.generateApplicationsSummary(report);
|
||||
|
||||
return {
|
||||
report: [],
|
||||
summary: null,
|
||||
report,
|
||||
summary,
|
||||
fromArchive: false,
|
||||
lastUpdated: new Date(),
|
||||
};
|
||||
} else {
|
||||
const [report, summary] = await this.reportService.decryptRiskInsightsReport(
|
||||
const [report, summary] = await this.reportDecipherService.decryptRiskInsightsReport(
|
||||
organizationId as OrganizationId,
|
||||
reportFromArchive,
|
||||
);
|
||||
@@ -106,14 +115,9 @@ export class RiskInsightsDataService {
|
||||
)
|
||||
.subscribe({
|
||||
next: ({ report, summary, fromArchive, lastUpdated }) => {
|
||||
// in this block, only set the applicationsSubject and appsSummarySubject if the report is from archive
|
||||
// the fetchApplicationsReport will set them if the report is not from archive
|
||||
if (fromArchive) {
|
||||
this.applicationsSubject.next(report);
|
||||
this.errorSubject.next(null);
|
||||
this.appsSummarySubject.next(summary);
|
||||
}
|
||||
|
||||
this.applicationsSubject.next(report);
|
||||
this.errorSubject.next(null);
|
||||
this.appsSummarySubject.next(summary);
|
||||
this.isReportFromArchiveSubject.next(fromArchive);
|
||||
this.dataLastUpdatedSubject.next(lastUpdated);
|
||||
},
|
||||
@@ -150,7 +154,8 @@ export class RiskInsightsDataService {
|
||||
}
|
||||
|
||||
refreshApplicationsReport(organizationId: string): void {
|
||||
this.fetchApplicationsReport(organizationId, true);
|
||||
this.isLoadingData(true);
|
||||
this.fetchApplicationsReportFromCache(organizationId, true);
|
||||
}
|
||||
|
||||
isActiveDrawerType = (drawerType: DrawerType): boolean => {
|
||||
|
||||
@@ -3,14 +3,10 @@ import { firstValueFrom } from "rxjs";
|
||||
import { ZXCVBNResult } from "zxcvbn";
|
||||
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { mockCiphers } from "./ciphers.mock";
|
||||
import { CriticalAppsService } from "./critical-apps.service";
|
||||
import { MemberCipherDetailsApiService } from "./member-cipher-details-api.service";
|
||||
import { mockMemberCipherDetails } from "./member-cipher-details-api.service.spec";
|
||||
import { RiskInsightsReportService } from "./risk-insights-report.service";
|
||||
@@ -21,10 +17,6 @@ describe("RiskInsightsReportService", () => {
|
||||
const auditService = mock<AuditService>();
|
||||
const cipherService = mock<CipherService>();
|
||||
const memberCipherDetailsService = mock<MemberCipherDetailsApiService>();
|
||||
const keyService = mock<KeyService>();
|
||||
const encryptService = mock<EncryptService>();
|
||||
const criticalAppsService = mock<CriticalAppsService>();
|
||||
const keyGenerationService = mock<KeyGenerationService>();
|
||||
|
||||
beforeEach(() => {
|
||||
pwdStrengthService.getPasswordStrength.mockImplementation((password: string) => {
|
||||
@@ -45,10 +37,6 @@ describe("RiskInsightsReportService", () => {
|
||||
auditService,
|
||||
cipherService,
|
||||
memberCipherDetailsService,
|
||||
keyService,
|
||||
encryptService,
|
||||
criticalAppsService,
|
||||
keyGenerationService,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,16 +3,11 @@
|
||||
import { concatMap, first, from, map, Observable, zip } from "rxjs";
|
||||
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import {
|
||||
ApplicationHealthReportDetail,
|
||||
@@ -25,12 +20,9 @@ import {
|
||||
MemberDetailsFlat,
|
||||
WeakPasswordDetail,
|
||||
WeakPasswordScore,
|
||||
RiskInsightsReport,
|
||||
GetRiskInsightsReportResponse,
|
||||
ApplicationHealthReportDetailWithCriticalFlagAndCipher,
|
||||
} from "../models/password-health";
|
||||
|
||||
import { CriticalAppsService } from "./critical-apps.service";
|
||||
import { MemberCipherDetailsApiService } from "./member-cipher-details-api.service";
|
||||
|
||||
export class RiskInsightsReportService {
|
||||
@@ -39,10 +31,6 @@ export class RiskInsightsReportService {
|
||||
private auditService: AuditService,
|
||||
private cipherService: CipherService,
|
||||
private memberCipherDetailsApiService: MemberCipherDetailsApiService,
|
||||
private keyService: KeyService,
|
||||
private encryptService: EncryptService,
|
||||
private criticalAppsService: CriticalAppsService,
|
||||
private keyGeneratorService: KeyGenerationService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -177,89 +165,12 @@ export class RiskInsightsReportService {
|
||||
};
|
||||
}
|
||||
|
||||
async generateEncryptedRiskInsightsReport(
|
||||
organizationId: OrganizationId,
|
||||
details: ApplicationHealthReportDetail[],
|
||||
summary: ApplicationHealthReportSummary,
|
||||
): Promise<RiskInsightsReport> {
|
||||
const orgKey = await this.keyService.getOrgKey(organizationId as string);
|
||||
if (orgKey === null) {
|
||||
throw new Error("Organization key not found");
|
||||
}
|
||||
|
||||
const reportWithSummary = { details, summary };
|
||||
|
||||
const reportContentEncryptionKey = await this.keyGeneratorService.createKey(512);
|
||||
|
||||
const reportEncrypted = await this.encryptService.encryptString(
|
||||
JSON.stringify(reportWithSummary),
|
||||
reportContentEncryptionKey,
|
||||
);
|
||||
|
||||
const wrappedReportContentEncryptionKey = await this.encryptService.wrapSymmetricKey(
|
||||
reportContentEncryptionKey,
|
||||
orgKey,
|
||||
);
|
||||
|
||||
const reportDataWithWrappedKey = {
|
||||
data: reportEncrypted.encryptedString,
|
||||
key: wrappedReportContentEncryptionKey.encryptedString,
|
||||
};
|
||||
|
||||
const riskInsightReport = {
|
||||
organizationId: organizationId,
|
||||
date: new Date().toISOString(),
|
||||
reportData: JSON.stringify(reportDataWithWrappedKey),
|
||||
totalMembers: 0,
|
||||
totalAtRiskMembers: 0,
|
||||
totalApplications: 0,
|
||||
totalAtRiskApplications: 0,
|
||||
totalCriticalApplications: 0,
|
||||
};
|
||||
|
||||
return riskInsightReport;
|
||||
}
|
||||
|
||||
async decryptRiskInsightsReport(
|
||||
organizationId: OrganizationId,
|
||||
riskInsightsReportResponse: GetRiskInsightsReportResponse,
|
||||
): Promise<[ApplicationHealthReportDetail[], ApplicationHealthReportSummary]> {
|
||||
try {
|
||||
const orgKey = await this.keyService.getOrgKey(organizationId as string);
|
||||
if (orgKey === null) {
|
||||
throw new Error("Organization key not found");
|
||||
}
|
||||
|
||||
const reportDataInJson = JSON.parse(riskInsightsReportResponse.reportData);
|
||||
const reportEncrypted = reportDataInJson.data;
|
||||
const wrappedReportContentEncryptionKey = reportDataInJson.key;
|
||||
|
||||
const unwrappedReportContentEncryptionKey = await this.encryptService.unwrapSymmetricKey(
|
||||
new EncString(wrappedReportContentEncryptionKey),
|
||||
orgKey,
|
||||
);
|
||||
|
||||
const reportUnencrypted = await this.encryptService.decryptString(
|
||||
new EncString(reportEncrypted),
|
||||
unwrappedReportContentEncryptionKey,
|
||||
);
|
||||
|
||||
const reportWithSummary = JSON.parse(reportUnencrypted);
|
||||
const reportJson = reportWithSummary.details;
|
||||
const reportSummary = reportWithSummary.summary;
|
||||
|
||||
return [reportJson, reportSummary];
|
||||
} catch {
|
||||
return [null, null];
|
||||
}
|
||||
}
|
||||
|
||||
async identifyCiphers(
|
||||
data: ApplicationHealthReportDetail[],
|
||||
cipherViews: CipherView[],
|
||||
): Promise<ApplicationHealthReportDetailWithCriticalFlagAndCipher[]> {
|
||||
const dataWithCiphers = data.map(
|
||||
(app, index) =>
|
||||
(app) =>
|
||||
({
|
||||
...app,
|
||||
ciphers: cipherViews.filter((c) => app.cipherIds.some((a) => a === c.id)),
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
RiskInsightsDataService,
|
||||
RiskInsightsReportService,
|
||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights/services";
|
||||
import { ReportDecipherService } from "@bitwarden/bit-common/dirt/reports/risk-insights/services/report-decipher.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
@@ -34,15 +35,16 @@ import { RiskInsightsComponent } from "./risk-insights.component";
|
||||
AuditService,
|
||||
CipherService,
|
||||
MemberCipherDetailsApiService,
|
||||
KeyService,
|
||||
EncryptService,
|
||||
CriticalAppsService,
|
||||
KeyGenerationService,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: RiskInsightsDataService,
|
||||
deps: [RiskInsightsReportService, RiskInsightsApiService, CipherService],
|
||||
deps: [
|
||||
RiskInsightsReportService,
|
||||
RiskInsightsApiService,
|
||||
CipherService,
|
||||
ReportDecipherService,
|
||||
],
|
||||
},
|
||||
safeProvider({
|
||||
provide: CriticalAppsService,
|
||||
@@ -58,6 +60,11 @@ import { RiskInsightsComponent } from "./risk-insights.component";
|
||||
provide: RiskInsightsApiService,
|
||||
deps: [ApiService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: ReportDecipherService,
|
||||
useClass: ReportDecipherService,
|
||||
deps: [KeyService, EncryptService, KeyGenerationService],
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class AccessIntelligenceModule {}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
firstValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
switchMap,
|
||||
} from "rxjs";
|
||||
|
||||
@@ -25,6 +24,7 @@ import {
|
||||
ApplicationHealthReportDetailWithCriticalFlagAndCipher,
|
||||
ApplicationHealthReportSummary,
|
||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
|
||||
import { ReportDecipherService } from "@bitwarden/bit-common/dirt/reports/risk-insights/services/report-decipher.service";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
@@ -84,7 +84,7 @@ export class AllApplicationsComponent implements OnInit {
|
||||
};
|
||||
|
||||
destroyRef = inject(DestroyRef);
|
||||
isLoading$: Observable<boolean> = of(false);
|
||||
isLoading$: Observable<boolean> = this.dataService.isLoading$;
|
||||
|
||||
private atRiskInsightsReport = new BehaviorSubject<{
|
||||
data: ApplicationHealthReportDetailWithCriticalFlag[];
|
||||
@@ -102,8 +102,6 @@ export class AllApplicationsComponent implements OnInit {
|
||||
});
|
||||
|
||||
async ngOnInit() {
|
||||
this.isLoading$ = this.dataService.isLoading$;
|
||||
|
||||
this.dataService.isLoadingData(true);
|
||||
|
||||
const organizationId = this.activatedRoute.snapshot.paramMap.get("organizationId") ?? "";
|
||||
@@ -126,6 +124,7 @@ export class AllApplicationsComponent implements OnInit {
|
||||
this.dataService.cipherViewsForOrganization$,
|
||||
])
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(
|
||||
([
|
||||
report,
|
||||
@@ -160,7 +159,7 @@ export class AllApplicationsComponent implements OnInit {
|
||||
criticalApps,
|
||||
cipherViewsForOrg,
|
||||
}) => {
|
||||
if (report && organization) {
|
||||
if (!!report && organization) {
|
||||
const dataWithCiphers = await this.reportService.identifyCiphers(
|
||||
report,
|
||||
cipherViewsForOrg,
|
||||
@@ -178,31 +177,36 @@ export class AllApplicationsComponent implements OnInit {
|
||||
return { report: [], summary, isReportFromArchive, organization, criticalApps: [] };
|
||||
},
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
)
|
||||
.subscribe(({ report, summary, isReportFromArchive, organization }) => {
|
||||
if (report) {
|
||||
this.dataSource.data = report;
|
||||
}
|
||||
.subscribe({
|
||||
next: ({ report, summary, isReportFromArchive, organization }) => {
|
||||
if (report) {
|
||||
this.dataSource.data = report;
|
||||
}
|
||||
|
||||
if (summary) {
|
||||
this.applicationSummary = summary;
|
||||
}
|
||||
if (summary) {
|
||||
this.applicationSummary = summary;
|
||||
}
|
||||
|
||||
if (organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
if (organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
if (!isReportFromArchive && report && organization && summary) {
|
||||
this.atRiskInsightsReport.next({
|
||||
data: report,
|
||||
organization: organization,
|
||||
summary: summary,
|
||||
});
|
||||
}
|
||||
if (!isReportFromArchive && !!report && !!organization && !!summary) {
|
||||
this.atRiskInsightsReport.next({
|
||||
data: report,
|
||||
organization: organization,
|
||||
summary: summary,
|
||||
});
|
||||
}
|
||||
|
||||
if (!!report && !!summary && !!organization) {
|
||||
this.dataService.isLoadingData(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.dataService.isLoadingData(false);
|
||||
// this.dataService.isLoadingData(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +222,7 @@ export class AllApplicationsComponent implements OnInit {
|
||||
private accountService: AccountService,
|
||||
protected criticalAppsService: CriticalAppsService,
|
||||
protected riskInsightsApiService: RiskInsightsApiService,
|
||||
protected reportDecipherService: ReportDecipherService,
|
||||
) {
|
||||
this.searchControl.valueChanges
|
||||
.pipe(debounceTime(200), takeUntilDestroyed())
|
||||
@@ -229,7 +234,7 @@ export class AllApplicationsComponent implements OnInit {
|
||||
debounceTime(500),
|
||||
switchMap(async (report) => {
|
||||
if (report && report.organization?.id && report.data && report.summary) {
|
||||
const data = await this.reportService.generateEncryptedRiskInsightsReport(
|
||||
const data = await this.reportDecipherService.generateEncryptedRiskInsightsReport(
|
||||
report.organization.id as OrganizationId,
|
||||
report.data,
|
||||
report.summary,
|
||||
|
||||
Reference in New Issue
Block a user