1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-05 03:03:26 +00:00

Update index files, separate models, add file for map functions

This commit is contained in:
Leslie Tilton
2025-08-13 10:45:27 -05:00
parent e7a1ea78e1
commit fce1f32546
7 changed files with 272 additions and 169 deletions

View File

@@ -75,7 +75,7 @@
}
},
"noAppsInOrgTitle": {
"message": "No applications found in $ORG NAME$",
"message": "No application reports found in $ORG NAME$",
"placeholders": {
"org name": {
"content": "$1",
@@ -101,6 +101,9 @@
"applicationsMarkedAsCriticalSuccess": {
"message": "Applications marked as critical"
},
"applicationsMarkedAsCriticalFail": {
"message": "Failed to mark applications as critical"
},
"application": {
"message": "Application"
},
@@ -10850,5 +10853,8 @@
"example": "12-3456789"
}
}
},
"runRiskInsightsReport": {
"message": "Run Report"
}
}

View File

@@ -0,0 +1 @@
export * from "./risk-insights-data-mappers";

View File

@@ -0,0 +1,51 @@
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { MemberDetails } from "../models/report-models";
import { MemberCipherDetailsResponse } from "../response/member-cipher-details.response";
export function flattenMemberDetails(
memberCiphers: MemberCipherDetailsResponse[],
): MemberDetails[] {
return memberCiphers.flatMap((member) =>
member.cipherIds.map((cipherId) => ({
userGuid: member.userGuid,
userName: member.userName,
email: member.email,
cipherId,
})),
);
}
/**
* Trim the cipher uris down to get the password health application.
* The uri should only exist once after being trimmed. No duplication.
* Example:
* - Untrimmed Uris: https://gmail.com, gmail.com/login
* - Both would trim to gmail.com
* - The cipher trimmed uri list should only return on instance in the list
* @param cipher
* @returns distinct list of trimmed cipher uris
*/
export function getTrimmedCipherUris(cipher: CipherView): string[] {
const uris = cipher.login?.uris ?? [];
const uniqueDomains = new Set<string>();
uris.forEach((u: { uri: string }) => {
const domain = Utils.getDomain(u.uri) ?? u.uri;
uniqueDomains.add(domain);
});
return Array.from(uniqueDomains);
}
// Returns a deduplicated array of members by email
export function getUniqueMembers(orgMembers: MemberDetails[]): MemberDetails[] {
const existingEmails = new Set<string>();
return orgMembers.filter((member) => {
if (existingEmails.has(member.email)) {
return false;
}
existingEmails.add(member.email);
return true;
});
}

View File

@@ -1 +1,2 @@
export * from "./services";
export * from "./helpers";

View File

@@ -0,0 +1,49 @@
import { EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { PasswordHealthReportApplicationId, RiskInsightsReport } from "./report-models";
// -------------------- Password Health Report Models --------------------
/**
* Request to drop a password health report application
* Model is expected by the API endpoint
*/
export interface PasswordHealthReportApplicationDropRequest {
organizationId: OrganizationId;
passwordHealthReportApplicationIds: string[];
}
/**
* Response from the API after marking an app as critical
*/
export interface PasswordHealthReportApplicationsResponse {
id: PasswordHealthReportApplicationId;
organizationId: OrganizationId;
uri: string;
}
/*
* Request to save a password health report application
* Model is expected by the API endpoint
*/
export interface PasswordHealthReportApplicationsRequest {
organizationId: OrganizationId;
url: string;
}
// -------------------- Risk Insights Report Models --------------------
export interface SaveRiskInsightsReportRequest {
data: RiskInsightsReport;
}
export interface SaveRiskInsightsReportResponse {
id: string;
}
export interface GetRiskInsightsReportResponse {
id: string;
organizationId: OrganizationId;
// TODO Update to use creationDate from server
date: string;
reportData: EncryptedString;
contentEncryptionKey: EncryptedString;
}

View File

@@ -1,76 +1,9 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Opaque } from "type-fest";
import { EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { BadgeVariant } from "@bitwarden/components";
/**
* All applications report summary. The total members,
* total at risk members, application, and at risk application
* counts. Aggregated from all calculated applications
*/
export type ApplicationHealthReportSummary = {
totalMemberCount: number;
totalAtRiskMemberCount: number;
totalApplicationCount: number;
totalAtRiskApplicationCount: number;
};
/**
* All applications report detail. Application is the cipher
* uri. Has the at risk, password, and member information
*/
export type ApplicationHealthReportDetail = {
applicationName: string;
passwordCount: number;
atRiskPasswordCount: number;
atRiskCipherIds: string[];
memberCount: number;
atRiskMemberCount: number;
memberDetails: MemberDetailsFlat[];
atRiskMemberDetails: MemberDetailsFlat[];
cipherIds: string[];
};
export type ApplicationHealthReportDetailWithCriticalFlag = ApplicationHealthReportDetail & {
isMarkedAsCritical: boolean;
};
export type ApplicationHealthReportDetailWithCriticalFlagAndCipher =
ApplicationHealthReportDetailWithCriticalFlag & {
ciphers: CipherView[];
};
/**
* Breaks the cipher health info out by uri and passes
* along the password health and member info
*/
export type CipherHealthReportUriDetail = {
cipherId: string;
reusedPasswordCount: number;
weakPasswordDetail: WeakPasswordDetail;
exposedPasswordDetail: ExposedPasswordDetail;
cipherMembers: MemberDetailsFlat[];
trimmedUri: string;
cipher: CipherView;
};
/**
* Associates a cipher with it's essential information.
* Gets the password health details, cipher members, and
* the trimmed uris for the cipher
*/
export type CipherHealthReportDetail = CipherView & {
reusedPasswordCount: number;
weakPasswordDetail: WeakPasswordDetail;
exposedPasswordDetail: ExposedPasswordDetail;
cipherMembers: MemberDetailsFlat[];
trimmedUris: string[];
};
/**
* Weak password details containing the score
* and the score type for the label and badge
@@ -97,41 +30,6 @@ export type ExposedPasswordDetail = {
exposedXTimes: number;
} | null;
/**
* Flattened member details that associates an
* organization member to a cipher
*/
export type MemberDetailsFlat = {
userGuid: string;
userName: string;
email: string;
cipherId: string;
};
/**
* Member email with the number of at risk passwords
* At risk member detail that contains the email
* and the count of at risk ciphers
*/
export type AtRiskMemberDetail = {
email: string;
atRiskPasswordCount: number;
};
/*
* A list of applications and the count of
* at risk passwords for each application
*/
export type AtRiskApplicationDetail = {
applicationName: string;
atRiskPasswordCount: number;
};
export type AppAtRiskMembersDialogParams = {
members: MemberDetailsFlat[];
applicationName: string;
};
/*
* After data is encrypted, it is returned with the
* encryption key used to encrypt the data.
@@ -139,70 +37,5 @@ export type AppAtRiskMembersDialogParams = {
export interface EncryptedDataWithKey {
organizationId: OrganizationId;
encryptedData: EncryptedString;
encryptionKey: EncryptedString;
contentEncryptionKey: EncryptedString;
}
/**
* Request to drop a password health report application
* Model is expected by the API endpoint
*/
export interface PasswordHealthReportApplicationDropRequest {
organizationId: OrganizationId;
passwordHealthReportApplicationIds: string[];
}
/**
* Response from the API after marking an app as critical
*/
export interface PasswordHealthReportApplicationsResponse {
id: PasswordHealthReportApplicationId;
organizationId: OrganizationId;
uri: string;
}
/*
* Request to save a password health report application
* Model is expected by the API endpoint
*/
export interface PasswordHealthReportApplicationsRequest {
organizationId: OrganizationId;
url: string;
}
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum DrawerType {
None = 0,
AppAtRiskMembers = 1,
OrgAtRiskMembers = 2,
OrgAtRiskApps = 3,
}
export interface RiskInsightsReport {
organizationId: OrganizationId;
date: string;
reportData: string;
reportKey: string;
}
export interface ReportInsightsReportData {
data: ApplicationHealthReportDetail[];
summary: ApplicationHealthReportSummary;
}
export interface SaveRiskInsightsReportRequest {
data: RiskInsightsReport;
}
export interface SaveRiskInsightsReportResponse {
id: string;
}
export interface GetRiskInsightsReportResponse {
id: string;
organizationId: OrganizationId;
date: string;
reportData: EncryptedString;
reportKey: EncryptedString;
}
export type PasswordHealthReportApplicationId = Opaque<string, "PasswordHealthReportApplicationId">;

View File

@@ -0,0 +1,162 @@
import { Opaque } from "type-fest";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { BadgeVariant } from "@bitwarden/components";
import { ExposedPasswordDetail, WeakPasswordDetail } from "./password-health";
// -------------------- Drawer and UI Models --------------------
// FIXME: update to use a const object instead of a typescript enum
// eslint-disable-next-line @bitwarden/platform/no-enums
export enum DrawerType {
None = 0,
AppAtRiskMembers = 1,
OrgAtRiskMembers = 2,
OrgAtRiskApps = 3,
}
export type DrawerDetails = {
open: boolean;
invokerId: string;
activeDrawerType: DrawerType;
atRiskMemberDetails?: AtRiskMemberDetail[];
appAtRiskMembers?: AppAtRiskMembersDialogParams | null;
atRiskAppDetails?: AtRiskApplicationDetail[] | null;
};
export type AppAtRiskMembersDialogParams = {
members: MemberDetails[];
applicationName: string;
};
// -------------------- Member Models --------------------
/**
* Member email with the number of at risk passwords
* At risk member detail that contains the email
* and the count of at risk ciphers
*/
export type AtRiskMemberDetail = {
email: string;
atRiskPasswordCount: number;
};
/**
* Flattened member details that associates an
* organization member to a cipher
*/
export type MemberDetails = {
userGuid: string;
userName: string;
email: string;
cipherId: string;
};
// -------------------- Cipher Models --------------------
export type PasswordHealthData = {
reusedPasswordCount: number;
weakPasswordDetail: WeakPasswordDetail;
exposedPasswordDetail: ExposedPasswordDetail;
};
/**
* Associates a cipher with it's essential information.
* Gets the password health details, cipher members, and
* the trimmed uris for the cipher
*/
export type CipherHealthReport = {
applications: string[];
cipherMembers: MemberDetails[];
healthData: PasswordHealthData;
cipher: CipherView;
};
/**
* Breaks the cipher health info out by uri and passes
* along the password health and member info
*/
export type CipherApplicationView = {
cipherId: string;
cipher: CipherView;
cipherMembers: MemberDetails[];
application: string;
healthData: PasswordHealthData;
};
// -------------------- Application Health Report Models --------------------
/**
* All applications report summary. The total members,
* total at risk members, application, and at risk application
* counts. Aggregated from all calculated applications
*/
export type ApplicationHealthReportSummary = {
totalMemberCount: number;
totalAtRiskMemberCount: number;
totalApplicationCount: number;
totalAtRiskApplicationCount: number;
};
export type CriticalSummaryDetails = {
totalCriticalMembersCount: number;
totalCriticalApplicationsCount: number;
};
/**
* All applications report detail. Application is the cipher
* uri. Has the at risk, password, and member information
*/
export type ApplicationHealthReportDetail = {
applicationName: string;
passwordCount: number;
atRiskPasswordCount: number;
atRiskCipherIds: string[];
memberCount: number;
atRiskMemberCount: number;
memberDetails: MemberDetails[];
atRiskMemberDetails: MemberDetails[];
cipherIds: string[];
};
export type ApplicationHealthReportDetailEnriched = ApplicationHealthReportDetail & {
isMarkedAsCritical: boolean;
ciphers: CipherView[];
};
/*
* A list of applications and the count of
* at risk passwords for each application
*/
export type AtRiskApplicationDetail = {
applicationName: string;
atRiskPasswordCount: number;
};
// -------------------- Password Health Report Models --------------------
export type PasswordHealthReportApplicationId = Opaque<string, "PasswordHealthReportApplicationId">;
// -------------------- Risk Insights Report Models --------------------
export interface RiskInsightsReportData {
data: ApplicationHealthReportDetailEnriched[];
summary: ApplicationHealthReportSummary;
}
export interface RiskInsightsReport {
organizationId: OrganizationId;
date: string;
reportData: string;
reportKey: string;
}
export type ReportScore = { label: string; badgeVariant: BadgeVariant; sortOrder: number };
export type ReportResult = CipherView & {
score: number;
reportValue: ReportScore;
scoreKey: number;
};
export type ReportDetailsAndSummary = {
data: ApplicationHealthReportDetailEnriched[];
summary: ApplicationHealthReportSummary;
dateCreated: Date;
};