diff --git a/bitwarden_license/bit-common/src/tools/reports/risk-insights/models/password-health.ts b/bitwarden_license/bit-common/src/tools/reports/risk-insights/models/password-health.ts index 2260f9257ad..723d737d5bd 100644 --- a/bitwarden_license/bit-common/src/tools/reports/risk-insights/models/password-health.ts +++ b/bitwarden_license/bit-common/src/tools/reports/risk-insights/models/password-health.ts @@ -85,6 +85,7 @@ export type WeakPasswordScore = { * How many times a password has been exposed */ export type ExposedPasswordDetail = { + cipherId: string; exposedXTimes: number; } | null; diff --git a/bitwarden_license/bit-common/src/tools/reports/risk-insights/services/risk-insights-report.service.ts b/bitwarden_license/bit-common/src/tools/reports/risk-insights/services/risk-insights-report.service.ts index c3bcc59eca5..027760f678c 100644 --- a/bitwarden_license/bit-common/src/tools/reports/risk-insights/services/risk-insights-report.service.ts +++ b/bitwarden_license/bit-common/src/tools/reports/risk-insights/services/risk-insights-report.service.ts @@ -175,6 +175,7 @@ export class RiskInsightsReportService { ): Promise { const cipherHealthReports: CipherHealthReportDetail[] = []; const passwordUseMap = new Map(); + const exposedDetails = await this.findExposedPasswords(ciphers); for (const cipher of ciphers) { if (this.validateCipher(cipher)) { const weakPassword = this.findWeakPassword(cipher); @@ -189,7 +190,7 @@ export class RiskInsightsReportService { passwordUseMap.set(cipher.login.password, 1); } - const exposedPassword = await this.findExposedPassword(cipher); + const exposedPassword = exposedDetails.find((x) => x.cipherId === cipher.id); // Get the cipher members const cipherMembers = memberDetails.filter((x) => x.cipherId === cipher.id); @@ -255,13 +256,29 @@ export class RiskInsightsReportService { return appReports; } - private async findExposedPassword(cipher: CipherView): Promise { - const exposedCount = await this.auditService.passwordLeaked(cipher.login.password); - if (exposedCount > 0) { - const exposedDetail = { exposedXTimes: exposedCount } as ExposedPasswordDetail; - return exposedDetail; - } - return null; + private async findExposedPasswords(ciphers: CipherView[]): Promise { + const exposedDetails: ExposedPasswordDetail[] = []; + const promises: Promise[] = []; + + ciphers.forEach((ciph) => { + if (this.validateCipher(ciph)) { + const promise = this.auditService + .passwordLeaked(ciph.login.password) + .then((exposedCount) => { + if (exposedCount > 0) { + const detail = { + exposedXTimes: exposedCount, + cipherId: ciph.id, + } as ExposedPasswordDetail; + exposedDetails.push(detail); + } + }); + promises.push(promise); + } + }); + await Promise.all(promises); + + return exposedDetails; } private findWeakPassword(cipher: CipherView): WeakPasswordDetail {