mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-25614] Add Encrichment Logic for Risk Insights Data Service (#16577)
* Add encryption logic. Minor updates to critical apps service * Fix possibly null type
This commit is contained in:
@@ -117,7 +117,7 @@ export type OrganizationReportApplication = {
|
||||
};
|
||||
|
||||
/**
|
||||
* All applications report detail. Application is the cipher
|
||||
* Report details for an application
|
||||
* uri. Has the at risk, password, and member information
|
||||
*/
|
||||
export type ApplicationHealthReportDetail = {
|
||||
|
||||
@@ -70,7 +70,7 @@ describe("CriticalAppsService", () => {
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
|
||||
// act
|
||||
await service.setCriticalApps(SomeOrganization, criticalApps);
|
||||
@@ -112,7 +112,7 @@ describe("CriticalAppsService", () => {
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
|
||||
// act
|
||||
await service.setCriticalApps(SomeOrganization, selectedUrls);
|
||||
@@ -136,7 +136,7 @@ describe("CriticalAppsService", () => {
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
|
||||
expect(keyService.orgKeys$).toHaveBeenCalledWith(SomeUser);
|
||||
expect(encryptService.decryptString).toHaveBeenCalledTimes(2);
|
||||
@@ -154,7 +154,7 @@ describe("CriticalAppsService", () => {
|
||||
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
service.setAppsInListForOrg(response);
|
||||
service.getAppsListForOrg(orgId as OrganizationId).subscribe((res) => {
|
||||
expect(res).toHaveLength(2);
|
||||
@@ -173,7 +173,7 @@ describe("CriticalAppsService", () => {
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
|
||||
service.setAppsInListForOrg(initialList);
|
||||
|
||||
@@ -204,7 +204,7 @@ describe("CriticalAppsService", () => {
|
||||
const orgKey$ = new BehaviorSubject(OrgRecords);
|
||||
keyService.orgKeys$.mockReturnValue(orgKey$);
|
||||
|
||||
service.setOrganizationId(SomeOrganization, SomeUser);
|
||||
service.loadOrganizationContext(SomeOrganization, SomeUser);
|
||||
|
||||
service.setAppsInListForOrg(initialList);
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import {
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
zip,
|
||||
} from "rxjs";
|
||||
|
||||
@@ -30,17 +28,16 @@ import { CriticalAppsApiService } from "./critical-apps-api.service";
|
||||
* Encrypts and saves data for a given organization
|
||||
*/
|
||||
export class CriticalAppsService {
|
||||
private orgId = new BehaviorSubject<OrganizationId | null>(null);
|
||||
// -------------------------- Context state --------------------------
|
||||
// The organization ID of the organization the user is currently viewing
|
||||
private organizationId = new BehaviorSubject<OrganizationId | null>(null);
|
||||
private orgKey$ = new Observable<OrgKey>();
|
||||
private criticalAppsList = new BehaviorSubject<PasswordHealthReportApplicationsResponse[]>([]);
|
||||
private teardown = new Subject<void>();
|
||||
|
||||
private fetchOrg$ = this.orgId
|
||||
.pipe(
|
||||
switchMap((orgId) => this.retrieveCriticalApps(orgId)),
|
||||
takeUntil(this.teardown),
|
||||
)
|
||||
.subscribe((apps) => this.criticalAppsList.next(apps));
|
||||
// -------------------------- Data ------------------------------------
|
||||
private criticalAppsListSubject$ = new BehaviorSubject<
|
||||
PasswordHealthReportApplicationsResponse[]
|
||||
>([]);
|
||||
criticalAppsList$ = this.criticalAppsListSubject$.asObservable();
|
||||
|
||||
constructor(
|
||||
private keyService: KeyService,
|
||||
@@ -48,25 +45,52 @@ export class CriticalAppsService {
|
||||
private criticalAppsApiService: CriticalAppsApiService,
|
||||
) {}
|
||||
|
||||
// Set context for the service for a specific organization
|
||||
loadOrganizationContext(orgId: OrganizationId, userId: UserId) {
|
||||
// Fetch the organization key for the user
|
||||
this.orgKey$ = this.keyService.orgKeys$(userId).pipe(
|
||||
filter((OrgKeys) => !!OrgKeys),
|
||||
map((organizationKeysById) => organizationKeysById[orgId as OrganizationId]),
|
||||
);
|
||||
|
||||
// Store organization id for service context
|
||||
this.organizationId.next(orgId);
|
||||
|
||||
// Setup the critical apps fetching for the organization
|
||||
if (orgId) {
|
||||
this.retrieveCriticalApps(orgId).subscribe({
|
||||
next: (result) => {
|
||||
this.criticalAppsListSubject$.next(result);
|
||||
},
|
||||
error: (error: unknown) => {
|
||||
throw error;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of critical apps for a given organization
|
||||
getAppsListForOrg(orgId: OrganizationId): Observable<PasswordHealthReportApplicationsResponse[]> {
|
||||
if (orgId != this.orgId.value) {
|
||||
throw new Error("Organization ID mismatch");
|
||||
// [FIXME] Get organization id from context for all functions in this file
|
||||
if (orgId != this.organizationId.value) {
|
||||
throw new Error(
|
||||
`Organization ID mismatch: expected ${this.organizationId.value}, got ${orgId}`,
|
||||
);
|
||||
}
|
||||
|
||||
return this.criticalAppsList
|
||||
return this.criticalAppsListSubject$
|
||||
.asObservable()
|
||||
.pipe(map((apps) => apps.filter((app) => app.organizationId === orgId)));
|
||||
}
|
||||
|
||||
// Reset the critical apps list
|
||||
setAppsInListForOrg(apps: PasswordHealthReportApplicationsResponse[]) {
|
||||
this.criticalAppsList.next(apps);
|
||||
this.criticalAppsListSubject$.next(apps);
|
||||
}
|
||||
|
||||
// Save the selected critical apps for a given organization
|
||||
async setCriticalApps(orgId: OrganizationId, selectedUrls: string[]) {
|
||||
if (orgId != this.orgId.value) {
|
||||
if (orgId != this.organizationId.value) {
|
||||
throw new Error("Organization ID mismatch");
|
||||
}
|
||||
|
||||
@@ -79,7 +103,7 @@ export class CriticalAppsService {
|
||||
// only save records that are not already in the database
|
||||
const newEntries = await this.filterNewEntries(orgId as OrganizationId, selectedUrls);
|
||||
const criticalAppsRequests = await this.encryptNewEntries(
|
||||
this.orgId.value as OrganizationId,
|
||||
this.organizationId.value as OrganizationId,
|
||||
orgKey,
|
||||
newEntries,
|
||||
);
|
||||
@@ -89,7 +113,7 @@ export class CriticalAppsService {
|
||||
);
|
||||
|
||||
// add the new entries to the criticalAppsList
|
||||
const updatedList = [...this.criticalAppsList.value];
|
||||
const updatedList = [...this.criticalAppsListSubject$.value];
|
||||
for (const responseItem of dbResponse) {
|
||||
const decryptedUrl = await this.encryptService.decryptString(
|
||||
new EncString(responseItem.uri),
|
||||
@@ -103,26 +127,17 @@ export class CriticalAppsService {
|
||||
} as PasswordHealthReportApplicationsResponse);
|
||||
}
|
||||
}
|
||||
this.criticalAppsList.next(updatedList);
|
||||
}
|
||||
|
||||
// Get the critical apps for a given organization
|
||||
setOrganizationId(orgId: OrganizationId, userId: UserId) {
|
||||
this.orgKey$ = this.keyService.orgKeys$(userId).pipe(
|
||||
filter((OrgKeys) => !!OrgKeys),
|
||||
map((organizationKeysById) => organizationKeysById[orgId as OrganizationId]),
|
||||
);
|
||||
this.orgId.next(orgId);
|
||||
this.criticalAppsListSubject$.next(updatedList);
|
||||
}
|
||||
|
||||
// Drop a critical app for a given organization
|
||||
// Only one app may be dropped at a time
|
||||
async dropCriticalApp(orgId: OrganizationId, selectedUrl: string) {
|
||||
if (orgId != this.orgId.value) {
|
||||
if (orgId != this.organizationId.value) {
|
||||
throw new Error("Organization ID mismatch");
|
||||
}
|
||||
|
||||
const app = this.criticalAppsList.value.find(
|
||||
const app = this.criticalAppsListSubject$.value.find(
|
||||
(f) => f.organizationId === orgId && f.uri === selectedUrl,
|
||||
);
|
||||
|
||||
@@ -135,7 +150,9 @@ export class CriticalAppsService {
|
||||
passwordHealthReportApplicationIds: [app.id],
|
||||
});
|
||||
|
||||
this.criticalAppsList.next(this.criticalAppsList.value.filter((f) => f.uri !== selectedUrl));
|
||||
this.criticalAppsListSubject$.next(
|
||||
this.criticalAppsListSubject$.value.filter((f) => f.uri !== selectedUrl),
|
||||
);
|
||||
}
|
||||
|
||||
private retrieveCriticalApps(
|
||||
@@ -170,7 +187,7 @@ export class CriticalAppsService {
|
||||
}
|
||||
|
||||
private async filterNewEntries(orgId: OrganizationId, selectedUrls: string[]): Promise<string[]> {
|
||||
return await firstValueFrom(this.criticalAppsList).then((criticalApps) => {
|
||||
return await firstValueFrom(this.criticalAppsListSubject$).then((criticalApps) => {
|
||||
const criticalAppsUri = criticalApps
|
||||
.filter((f) => f.organizationId === orgId)
|
||||
.map((f) => f.uri);
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { finalize } from "rxjs/operators";
|
||||
import { BehaviorSubject, firstValueFrom, Observable, of } from "rxjs";
|
||||
import { finalize, switchMap, withLatestFrom } from "rxjs/operators";
|
||||
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
getOrganizationById,
|
||||
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 { OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import {
|
||||
AppAtRiskMembersDialogParams,
|
||||
@@ -9,14 +15,35 @@ import {
|
||||
AtRiskMemberDetail,
|
||||
DrawerType,
|
||||
ApplicationHealthReportDetail,
|
||||
ApplicationHealthReportDetailEnriched,
|
||||
} from "../models/report-models";
|
||||
|
||||
import { CriticalAppsService } from "./critical-apps.service";
|
||||
import { RiskInsightsReportService } from "./risk-insights-report.service";
|
||||
export class RiskInsightsDataService {
|
||||
private applicationsSubject = new BehaviorSubject<ApplicationHealthReportDetail[] | null>(null);
|
||||
// -------------------------- Context state --------------------------
|
||||
// Current user viewing risk insights
|
||||
private userIdSubject = new BehaviorSubject<UserId | null>(null);
|
||||
userId$ = this.userIdSubject.asObservable();
|
||||
|
||||
// Organization the user is currently viewing
|
||||
private organizationDetailsSubject = new BehaviorSubject<{
|
||||
organizationId: OrganizationId;
|
||||
organizationName: string;
|
||||
} | null>(null);
|
||||
organizationDetails$ = this.organizationDetailsSubject.asObservable();
|
||||
|
||||
// -------------------------- Data ------------------------------------
|
||||
private applicationsSubject = new BehaviorSubject<ApplicationHealthReportDetail[] | null>(null);
|
||||
applications$ = this.applicationsSubject.asObservable();
|
||||
|
||||
private dataLastUpdatedSubject = new BehaviorSubject<Date | null>(null);
|
||||
dataLastUpdated$ = this.dataLastUpdatedSubject.asObservable();
|
||||
|
||||
criticalApps$ = this.criticalAppsService.criticalAppsList$;
|
||||
|
||||
// --------------------------- UI State ------------------------------------
|
||||
|
||||
private isLoadingSubject = new BehaviorSubject<boolean>(false);
|
||||
isLoading$ = this.isLoadingSubject.asObservable();
|
||||
|
||||
@@ -26,9 +53,6 @@ export class RiskInsightsDataService {
|
||||
private errorSubject = new BehaviorSubject<string | null>(null);
|
||||
error$ = this.errorSubject.asObservable();
|
||||
|
||||
private dataLastUpdatedSubject = new BehaviorSubject<Date | null>(null);
|
||||
dataLastUpdated$ = this.dataLastUpdatedSubject.asObservable();
|
||||
|
||||
openDrawer = false;
|
||||
drawerInvokerId: string = "";
|
||||
activeDrawerType: DrawerType = DrawerType.None;
|
||||
@@ -36,7 +60,51 @@ export class RiskInsightsDataService {
|
||||
appAtRiskMembers: AppAtRiskMembersDialogParams | null = null;
|
||||
atRiskAppDetails: AtRiskApplicationDetail[] | null = null;
|
||||
|
||||
constructor(private reportService: RiskInsightsReportService) {}
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private criticalAppsService: CriticalAppsService,
|
||||
private organizationService: OrganizationService,
|
||||
private reportService: RiskInsightsReportService,
|
||||
) {}
|
||||
|
||||
// [FIXME] PM-25612 - Call Initialization in RiskInsightsComponent instead of child components
|
||||
async initializeForOrganization(organizationId: OrganizationId) {
|
||||
// Fetch current user
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (userId) {
|
||||
this.userIdSubject.next(userId);
|
||||
}
|
||||
|
||||
// [FIXME] getOrganizationById is now deprecated - update when we can
|
||||
// Fetch organization details
|
||||
const org = await firstValueFrom(
|
||||
this.organizationService.organizations$(userId).pipe(getOrganizationById(organizationId)),
|
||||
);
|
||||
if (org) {
|
||||
this.organizationDetailsSubject.next({
|
||||
organizationId: organizationId,
|
||||
organizationName: org.name,
|
||||
});
|
||||
}
|
||||
|
||||
// Load critical applications for organization
|
||||
await this.criticalAppsService.loadOrganizationContext(organizationId, userId);
|
||||
|
||||
// TODO: PM-25613
|
||||
// // Load existing report
|
||||
|
||||
// this.fetchLastReport(organizationId, userId);
|
||||
|
||||
// // Setup new report generation
|
||||
// this._runApplicationsReport().subscribe({
|
||||
// next: (result) => {
|
||||
// this.isRunningReportSubject.next(false);
|
||||
// },
|
||||
// error: () => {
|
||||
// this.errorSubject.next("Failed to save report");
|
||||
// },
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the applications report and updates the applicationsSubject.
|
||||
@@ -72,6 +140,44 @@ export class RiskInsightsDataService {
|
||||
this.fetchApplicationsReport(organizationId, true);
|
||||
}
|
||||
|
||||
// ------------------------------- Enrichment methods -------------------------------
|
||||
/**
|
||||
* Takes the basic application health report details and enriches them to include
|
||||
* critical app status and associated ciphers.
|
||||
*
|
||||
* @param applications The list of application health report details to enrich
|
||||
* @returns The enriched application health report details with critical app status and ciphers
|
||||
*/
|
||||
enrichReportData$(
|
||||
applications: ApplicationHealthReportDetail[],
|
||||
): Observable<ApplicationHealthReportDetailEnriched[]> {
|
||||
return of(applications).pipe(
|
||||
withLatestFrom(this.organizationDetails$, this.criticalApps$),
|
||||
switchMap(async ([apps, orgDetails, criticalApps]) => {
|
||||
if (!orgDetails) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Get ciphers for application
|
||||
const cipherMap = await this.reportService.getApplicationCipherMap(
|
||||
apps,
|
||||
orgDetails.organizationId,
|
||||
);
|
||||
|
||||
// Find critical apps
|
||||
const criticalApplicationNames = new Set(criticalApps.map((ca) => ca.uri));
|
||||
|
||||
// Return enriched application data
|
||||
return apps.map((app) => ({
|
||||
...app,
|
||||
ciphers: cipherMap.get(app.applicationName) || [],
|
||||
isMarkedAsCritical: criticalApplicationNames.has(app.applicationName),
|
||||
})) as ApplicationHealthReportDetailEnriched[];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------- Drawer management methods -------------------------------
|
||||
isActiveDrawerType = (drawerType: DrawerType): boolean => {
|
||||
return this.activeDrawerType === drawerType;
|
||||
};
|
||||
|
||||
@@ -59,15 +59,6 @@ import { RiskInsightsApiService } from "./risk-insights-api.service";
|
||||
import { RiskInsightsEncryptionService } from "./risk-insights-encryption.service";
|
||||
|
||||
export class RiskInsightsReportService {
|
||||
constructor(
|
||||
private passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||
private auditService: AuditService,
|
||||
private cipherService: CipherService,
|
||||
private memberCipherDetailsApiService: MemberCipherDetailsApiService,
|
||||
private riskInsightsApiService: RiskInsightsApiService,
|
||||
private riskInsightsEncryptionService: RiskInsightsEncryptionService,
|
||||
) {}
|
||||
|
||||
private riskInsightsReportSubject = new BehaviorSubject<ApplicationHealthReportDetail[]>([]);
|
||||
riskInsightsReport$ = this.riskInsightsReportSubject.asObservable();
|
||||
|
||||
@@ -84,6 +75,27 @@ export class RiskInsightsReportService {
|
||||
});
|
||||
riskInsightsSummary$ = this.riskInsightsSummarySubject.asObservable();
|
||||
|
||||
// [FIXME] CipherData
|
||||
// Cipher data
|
||||
// private _ciphersSubject = new BehaviorSubject<CipherView[] | null>(null);
|
||||
// _ciphers$ = this._ciphersSubject.asObservable();
|
||||
|
||||
constructor(
|
||||
private passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||
private auditService: AuditService,
|
||||
private cipherService: CipherService,
|
||||
private memberCipherDetailsApiService: MemberCipherDetailsApiService,
|
||||
private riskInsightsApiService: RiskInsightsApiService,
|
||||
private riskInsightsEncryptionService: RiskInsightsEncryptionService,
|
||||
) {}
|
||||
|
||||
// [FIXME] CipherData
|
||||
// async loadCiphersForOrganization(organizationId: OrganizationId): Promise<void> {
|
||||
// await this.cipherService.getAllFromApiForOrganization(organizationId).then((ciphers) => {
|
||||
// this._ciphersSubject.next(ciphers);
|
||||
// });
|
||||
// }
|
||||
|
||||
/**
|
||||
* Report data from raw cipher health data.
|
||||
* Can be used in the Raw Data diagnostic tab (just exclude the members in the view)
|
||||
@@ -559,6 +571,31 @@ export class RiskInsightsReportService {
|
||||
return applicationMap;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param applications The list of application health report details to map ciphers to
|
||||
* @param organizationId
|
||||
* @returns
|
||||
*/
|
||||
async getApplicationCipherMap(
|
||||
applications: ApplicationHealthReportDetail[],
|
||||
organizationId: OrganizationId,
|
||||
): Promise<Map<string, CipherView[]>> {
|
||||
// [FIXME] CipherData
|
||||
// This call is made multiple times. We can optimize this
|
||||
// by loading the ciphers once via a load method to avoid multiple API calls
|
||||
// for the same organization
|
||||
const allCiphers = await this.cipherService.getAllFromApiForOrganization(organizationId);
|
||||
const cipherMap = new Map<string, CipherView[]>();
|
||||
|
||||
applications.forEach((app) => {
|
||||
const filteredCiphers = allCiphers.filter((c) => app.cipherIds.includes(c.id));
|
||||
cipherMap.set(app.applicationName, filteredCiphers);
|
||||
});
|
||||
return cipherMap;
|
||||
}
|
||||
|
||||
// --------------------------- Aggregation methods ---------------------------
|
||||
/**
|
||||
* Loop through the flattened cipher to uri data. If the item exists it's values need to be updated with the new item.
|
||||
* If the item is new, create and add the object with the flattened details
|
||||
|
||||
@@ -11,6 +11,8 @@ import {
|
||||
import { RiskInsightsEncryptionService } from "@bitwarden/bit-common/dirt/reports/risk-insights/services/risk-insights-encryption.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/key-management/crypto";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength/password-strength.service.abstraction";
|
||||
@@ -36,10 +38,15 @@ import { RiskInsightsComponent } from "./risk-insights.component";
|
||||
MemberCipherDetailsApiService,
|
||||
],
|
||||
},
|
||||
{
|
||||
safeProvider({
|
||||
provide: RiskInsightsDataService,
|
||||
deps: [RiskInsightsReportService],
|
||||
},
|
||||
deps: [
|
||||
AccountServiceAbstraction,
|
||||
CriticalAppsService,
|
||||
OrganizationService,
|
||||
RiskInsightsReportService,
|
||||
],
|
||||
}),
|
||||
{
|
||||
provide: RiskInsightsEncryptionService,
|
||||
useClass: RiskInsightsEncryptionService,
|
||||
|
||||
@@ -66,40 +66,42 @@ export class CriticalApplicationsComponent implements OnInit {
|
||||
"organizationId",
|
||||
) as OrganizationId;
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.criticalAppsService.setOrganizationId(this.organizationId as OrganizationId, userId);
|
||||
// this.criticalAppsService.setOrganizationId(this.organizationId as OrganizationId);
|
||||
combineLatest([
|
||||
this.dataService.applications$,
|
||||
this.criticalAppsService.getAppsListForOrg(this.organizationId as OrganizationId),
|
||||
])
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(([applications, criticalApps]) => {
|
||||
const criticalUrls = criticalApps.map((ca) => ca.uri);
|
||||
const data = applications?.map((app) => ({
|
||||
...app,
|
||||
isMarkedAsCritical: criticalUrls.includes(app.applicationName),
|
||||
})) as LEGACY_ApplicationHealthReportDetailWithCriticalFlag[];
|
||||
return data?.filter((app) => app.isMarkedAsCritical);
|
||||
}),
|
||||
switchMap(async (data) => {
|
||||
if (data) {
|
||||
const dataWithCiphers = await this.reportService.identifyCiphers(
|
||||
data,
|
||||
this.organizationId,
|
||||
);
|
||||
return dataWithCiphers;
|
||||
this.criticalAppsService.loadOrganizationContext(this.organizationId as OrganizationId, userId);
|
||||
|
||||
if (this.organizationId) {
|
||||
combineLatest([
|
||||
this.dataService.applications$,
|
||||
this.criticalAppsService.getAppsListForOrg(this.organizationId as OrganizationId),
|
||||
])
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(([applications, criticalApps]) => {
|
||||
const criticalUrls = criticalApps.map((ca) => ca.uri);
|
||||
const data = applications?.map((app) => ({
|
||||
...app,
|
||||
isMarkedAsCritical: criticalUrls.includes(app.applicationName),
|
||||
})) as LEGACY_ApplicationHealthReportDetailWithCriticalFlag[];
|
||||
return data?.filter((app) => app.isMarkedAsCritical);
|
||||
}),
|
||||
switchMap(async (data) => {
|
||||
if (data) {
|
||||
const dataWithCiphers = await this.reportService.identifyCiphers(
|
||||
data,
|
||||
this.organizationId,
|
||||
);
|
||||
return dataWithCiphers;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
)
|
||||
.subscribe((applications) => {
|
||||
if (applications) {
|
||||
this.dataSource.data = applications;
|
||||
this.applicationSummary = this.reportService.generateApplicationsSummary(applications);
|
||||
this.enableRequestPasswordChange = this.applicationSummary.totalAtRiskMemberCount > 0;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
)
|
||||
.subscribe((applications) => {
|
||||
if (applications) {
|
||||
this.dataSource.data = applications;
|
||||
this.applicationSummary = this.reportService.generateApplicationsSummary(applications);
|
||||
this.enableRequestPasswordChange = this.applicationSummary.totalAtRiskMemberCount > 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
goToAllAppsTab = async () => {
|
||||
|
||||
@@ -127,7 +127,10 @@ export class RiskInsightsComponent implements OnInit {
|
||||
this.appsCount = applications.length;
|
||||
}
|
||||
|
||||
this.criticalAppsService.setOrganizationId(this.organizationId as OrganizationId, userId);
|
||||
this.criticalAppsService.loadOrganizationContext(
|
||||
this.organizationId as OrganizationId,
|
||||
userId,
|
||||
);
|
||||
this.criticalApps$ = this.criticalAppsService.getAppsListForOrg(
|
||||
this.organizationId as OrganizationId,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user