Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3a67038
Add password trigger logic to report service. Also updated api to useโ€ฆ
Banrion Sep 26, 2025
252cd9a
Merge branch 'main' into dirt/pm-25613/report-service-trigger
Banrion Sep 26, 2025
7c97f0a
Fix merged test case conflict
Banrion Sep 26, 2025
fac0102
Fix type errors and test cases. Make create data functions for reportโ€ฆ
Banrion Sep 28, 2025
0d48bad
Update Risk Insights Report Data Type
Banrion Sep 29, 2025
3191ac9
Update encryption usage and test cases. Moved mock data
Banrion Sep 29, 2025
cbf08b6
Remove unused variable
Banrion Sep 29, 2025
a4bd797
Move all-application constructor
Banrion Sep 29, 2025
e92eddb
Update all applications and risk insights to look at fetched logic
Banrion Sep 29, 2025
b9d6b84
Fix name of variable. Fetch last report run
Banrion Sep 29, 2025
f47e195
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Sep 30, 2025
bd456fc
Cleanup all and critical application tabs drawer dependencies
Banrion Sep 30, 2025
4fbf944
Rename components from tool to dirt. Hook up all applications to use โ€ฆ
Banrion Sep 30, 2025
d0eaf4b
Critical application cleanup. Trigger refetch of report for enrichingโ€ฆ
Banrion Sep 30, 2025
1378a2c
Fix type errors
Banrion Sep 30, 2025
0e54294
Rename loader from tools to dirt. Cleanup
Banrion Sep 30, 2025
72b0df7
Add activity tab updates using data service
Banrion Sep 30, 2025
695f98e
Use safeProviders in access intelligence
Banrion Sep 30, 2025
6a7570c
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Sep 30, 2025
97c45a8
Fix refresh button not appearing. Change "refresh" to "run report"
Banrion Oct 3, 2025
b4e8d26
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 3, 2025
0908b93
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 3, 2025
f2210d8
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 3, 2025
9c1ee08
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 3, 2025
1834b87
Merge remote-tracking branch 'refs/remotes/origin/dirt/pm-25611/removโ€ฆ
Banrion Oct 3, 2025
2c9ae8d
Remove multiple async calls for isRunningReport
Banrion Oct 3, 2025
9816bc7
Fix report button not showing
Banrion Oct 3, 2025
5666f05
Add no report ran message
Banrion Oct 3, 2025
43818f4
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 3, 2025
e590772
Fix password change on critical applications
Banrion Oct 6, 2025
c726eec
Merge branch 'main' into dirt/pm-25611/remove-client-duplication
Banrion Oct 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
}
}
},
"noReportRan": {
"message": "You have not created a report yet"
},
"notifiedMembers": {
"message": "Notified members"
},
Expand Down Expand Up @@ -187,6 +190,9 @@
"applicationsMarkedAsCriticalSuccess": {
"message": "Applications marked as critical"
},
"applicationsMarkedAsCriticalFail": {
"message": "Failed to mark applications as critical"
},
"application": {
"message": "Application"
},
Expand Down Expand Up @@ -4314,6 +4320,9 @@
"generatingYourRiskInsights": {
"message": "Generating your Risk Insights..."
},
"riskInsightsRunReport": {
"message": "Run report"
},
"updateBrowserDesc": {
"message": "You are using an unsupported web browser. The web vault may not function properly."
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import {
ApplicationHealthReportDetail,
OrganizationReportSummary,
RiskInsightsReportData,
RiskInsightsData,
} from "../models/report-models";
import { MemberCipherDetailsResponse } from "../response/member-cipher-details.response";

Expand Down Expand Up @@ -154,10 +154,12 @@ export function getApplicationReportDetail(
*
* @returns An empty report
*/
export function createNewReportData(): RiskInsightsReportData {
export function createNewReportData(): RiskInsightsData {
return {
data: [],
summary: createNewSummaryData(),
creationDate: new Date(),
reportData: [],
summaryData: createNewSummaryData(),
applicationData: [],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ export interface PasswordHealthReportApplicationsRequest {
export interface SaveRiskInsightsReportRequest {
data: {
organizationId: OrganizationId;
date: string;
creationDate: string;
reportData: string;
summaryData: string;
applicationData: string;
contentEncryptionKey: string;
};
}
Expand All @@ -58,34 +60,37 @@ export function isSaveRiskInsightsReportResponse(obj: any): obj is SaveRiskInsig
export class GetRiskInsightsReportResponse extends BaseResponse {
id: string;
organizationId: OrganizationId;
// TODO Update to use creationDate from server
date: string;
creationDate: Date;
reportData: EncString;
summaryData: EncString;
applicationData: EncString;
contentEncryptionKey: EncString;

constructor(response: any) {
super(response);

this.id = this.getResponseProperty("organizationId");
this.organizationId = this.getResponseProperty("organizationId");
this.date = this.getResponseProperty("date");
this.creationDate = new Date(this.getResponseProperty("creationDate"));
this.reportData = new EncString(this.getResponseProperty("reportData"));
this.summaryData = new EncString(this.getResponseProperty("summaryData"));
this.applicationData = new EncString(this.getResponseProperty("applicationData"));
this.contentEncryptionKey = new EncString(this.getResponseProperty("contentEncryptionKey"));
}
}

export class GetRiskInsightsSummaryResponse extends BaseResponse {
id: string;
organizationId: OrganizationId;
encryptedData: EncString; // Decrypted as OrganizationReportSummary
encryptedSummary: EncString; // Decrypted as OrganizationReportSummary
contentEncryptionKey: EncString;

constructor(response: any) {
super(response);
// TODO Handle taking array of summary data and converting to array
this.id = this.getResponseProperty("id");
this.organizationId = this.getResponseProperty("organizationId");
this.encryptedData = this.getResponseProperty("encryptedData");
this.encryptedSummary = this.getResponseProperty("encryptedData");
this.contentEncryptionKey = this.getResponseProperty("contentEncryptionKey");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./api-models.types";
export * from "./password-health";
export * from "./report-data-service.types";
export * from "./report-encryption.types";
export * from "./report-models";
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { mock } from "jest-mock-extended";

import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";

import { MemberCipherDetailsResponse } from "../response/member-cipher-details.response";

import { ApplicationHealthReportDetailEnriched } from "./report-data-service.types";
import {
ApplicationHealthReportDetail,
OrganizationReportApplication,
OrganizationReportSummary,
} from "./report-models";

const mockApplication1: ApplicationHealthReportDetail = {
applicationName: "application1.com",
passwordCount: 2,
atRiskPasswordCount: 1,
atRiskCipherIds: ["cipher-1"],
memberCount: 2,
atRiskMemberCount: 1,
memberDetails: [
{
userGuid: "user-id-1",
userName: "tom",
email: "[email protected]",
cipherId: "cipher-1",
},
],
atRiskMemberDetails: [
{
userGuid: "user-id-2",
userName: "tom",
email: "[email protected]",
cipherId: "cipher-2",
},
],
cipherIds: ["cipher-1", "cipher-2"],
};

const mockApplication2: ApplicationHealthReportDetail = {
applicationName: "site2.application1.com",
passwordCount: 0,
atRiskPasswordCount: 0,
atRiskCipherIds: [],
memberCount: 0,
atRiskMemberCount: 0,
memberDetails: [],
atRiskMemberDetails: [],
cipherIds: [],
};
const mockApplication3: ApplicationHealthReportDetail = {
applicationName: "application2.com",
passwordCount: 0,
atRiskPasswordCount: 0,
atRiskCipherIds: [],
memberCount: 0,
atRiskMemberCount: 0,
memberDetails: [],
atRiskMemberDetails: [],
cipherIds: [],
};

export const mockReportData: ApplicationHealthReportDetail[] = [
mockApplication1,
mockApplication2,
mockApplication3,
];

export const mockSummaryData: OrganizationReportSummary = {
totalMemberCount: 5,
totalAtRiskMemberCount: 2,
totalApplicationCount: 3,
totalAtRiskApplicationCount: 1,
totalCriticalMemberCount: 1,
totalCriticalAtRiskMemberCount: 1,
totalCriticalApplicationCount: 1,
totalCriticalAtRiskApplicationCount: 1,
newApplications: [],
};
export const mockApplicationData: OrganizationReportApplication[] = [
{
applicationName: "application1.com",
isCritical: true,
},
{
applicationName: "application2.com",
isCritical: false,
},
];

export const mockEnrichedReportData: ApplicationHealthReportDetailEnriched[] = [
{ ...mockApplication1, isMarkedAsCritical: true, ciphers: [] },
{ ...mockApplication2, isMarkedAsCritical: false, ciphers: [] },
];

export const mockCipherViews: CipherView[] = [
mock<CipherView>({
id: "cipher-1",
type: CipherType.Login,
login: { password: "pass1", username: "user1", uris: [{ uri: "https://app.com/login" }] },
isDeleted: false,
viewPassword: true,
}),
mock<CipherView>({
id: "cipher-2",
type: CipherType.Login,
login: { password: "pass2", username: "user2", uris: [{ uri: "app.com/home" }] },
isDeleted: false,
viewPassword: true,
}),
mock<CipherView>({
id: "cipher-3",
type: CipherType.Login,
login: { password: "pass3", username: "user3", uris: [{ uri: "https://other.com" }] },
isDeleted: false,
viewPassword: true,
}),
];

export const mockMemberDetails = [
mock<MemberCipherDetailsResponse>({
cipherIds: ["cipher-1"],
userGuid: "user1",
userName: "User 1",
email: "[email protected]",
}),
mock<MemberCipherDetailsResponse>({
cipherIds: ["cipher-2"],
userGuid: "user2",
userName: "User 2",
email: "[email protected]",
}),
mock<MemberCipherDetailsResponse>({
cipherIds: ["cipher-3"],
userGuid: "user3",
userName: "User 3",
email: "[email protected]",
}),
];
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { BadgeVariant } from "@bitwarden/components";

Expand Down Expand Up @@ -33,16 +31,6 @@ export type ExposedPasswordDetail = {
exposedXTimes: number;
} | null;

/*
* After data is encrypted, it is returned with the
* encryption key used to encrypt the data.
*/
export interface EncryptedDataWithKey {
organizationId: OrganizationId;
encryptedData: EncString;
contentEncryptionKey: EncString;
}

export type LEGACY_MemberDetailsFlat = {
userGuid: string;
userName: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";

import {
ApplicationHealthReportDetail,
OrganizationReportApplication,
OrganizationReportSummary,
} from "./report-models";

export type ApplicationHealthReportDetailEnriched = ApplicationHealthReportDetail & {
isMarkedAsCritical: boolean;
ciphers: CipherView[];
};
export interface RiskInsightsEnrichedData {
reportData: ApplicationHealthReportDetailEnriched[];
summaryData: OrganizationReportSummary;
applicationData: OrganizationReportApplication[];
creationDate: Date;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
import { OrganizationId } from "@bitwarden/common/types/guid";

import {
ApplicationHealthReportDetail,
OrganizationReportApplication,
OrganizationReportSummary,
} from "./report-models";

/*
* After data is encrypted, it is returned with the
* encryption key used to encrypt the data.
*/
export interface EncryptedDataWithKey {
organizationId: OrganizationId;
encryptedReportData: EncString;
encryptedSummaryData: EncString;
encryptedApplicationData: EncString;
contentEncryptionKey: EncString;
}

export interface DecryptedReportData {
reportData: ApplicationHealthReportDetail[];
summaryData: OrganizationReportSummary;
applicationData: OrganizationReportApplication[];
}

export interface EncryptedReportData {
encryptedReportData: EncString;
encryptedSummaryData: EncString;
encryptedApplicationData: EncString;
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,6 @@ export type ApplicationHealthReportDetail = {
cipherIds: string[];
};

export type ApplicationHealthReportDetailEnriched = ApplicationHealthReportDetail & {
isMarkedAsCritical: boolean;
ciphers: CipherView[];
};

/*
* A list of applications and the count of
* at risk passwords for each application
Expand All @@ -148,12 +143,6 @@ export type AtRiskApplicationDetail = {
// -------------------- Password Health Report Models --------------------
export type PasswordHealthReportApplicationId = Opaque<string, "PasswordHealthReportApplicationId">;

// -------------------- Risk Insights Report Models --------------------
export interface RiskInsightsReportData {
data: ApplicationHealthReportDetailEnriched[];
summary: OrganizationReportSummary;
}

export type ReportScore = { label: string; badgeVariant: BadgeVariant; sortOrder: number };

export type ReportResult = CipherView & {
Expand All @@ -162,8 +151,9 @@ export type ReportResult = CipherView & {
scoreKey: number;
};

export type ReportDetailsAndSummary = {
data: ApplicationHealthReportDetailEnriched[];
summary: OrganizationReportSummary;
dateCreated: Date;
};
export interface RiskInsightsData {
creationDate: Date;
reportData: ApplicationHealthReportDetail[];
summaryData: OrganizationReportSummary;
applicationData: OrganizationReportApplication[];
}
Loading
Loading