1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 09:43:23 +00:00

[PM-14813] - Implement server API to user member cipher details instead of mock data (#11978)

* use cipher details data

* fix failing tests

* fix failing tests
This commit is contained in:
Jordan Aasen
2024-11-13 08:37:29 -08:00
committed by GitHub
parent 379efb1326
commit 0b11596f08
9 changed files with 140 additions and 109 deletions

View File

@@ -4,74 +4,72 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { MemberCipherDetailsApiService } from "./member-cipher-details-api.service";
const mockMemberCipherDetails: any = {
data: [
{
userName: "David Brent",
email: "david.brent@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab1",
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Tim Canterbury",
email: "tim.canterbury@wernhamhogg.uk",
usesKeyConnector: false,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Gareth Keenan",
email: "gareth.keenan@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
"cbea34a8-bde4-46ad-9d19-b05001227nm7",
],
},
{
userName: "Dawn Tinsley",
email: "dawn.tinsley@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
],
},
{
userName: "Keith Bishop",
email: "keith.bishop@wernhamhogg.uk",
usesKeyConnector: false,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab1",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Chris Finch",
email: "chris.finch@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
],
},
],
};
export const mockMemberCipherDetails: any = [
{
userName: "David Brent",
email: "david.brent@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab1",
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Tim Canterbury",
email: "tim.canterbury@wernhamhogg.uk",
usesKeyConnector: false,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Gareth Keenan",
email: "gareth.keenan@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
"cbea34a8-bde4-46ad-9d19-b05001227nm7",
],
},
{
userName: "Dawn Tinsley",
email: "dawn.tinsley@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
],
},
{
userName: "Keith Bishop",
email: "keith.bishop@wernhamhogg.uk",
usesKeyConnector: false,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab1",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
"cbea34a8-bde4-46ad-9d19-b05001227nm5",
],
},
{
userName: "Chris Finch",
email: "chris.finch@wernhamhogg.uk",
usesKeyConnector: true,
cipherIds: [
"cbea34a8-bde4-46ad-9d19-b05001228ab2",
"cbea34a8-bde4-46ad-9d19-b05001228cd3",
"cbea34a8-bde4-46ad-9d19-b05001228xy4",
],
},
];
describe("Member Cipher Details API Service", () => {
let memberCipherDetailsApiService: MemberCipherDetailsApiService;

View File

@@ -1,8 +1,10 @@
import { Injectable } from "@angular/core";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { MemberCipherDetailsResponse } from "../response/member-cipher-details.response";
@Injectable()
export class MemberCipherDetailsApiService {
constructor(private apiService: ApiService) {}
@@ -21,7 +23,6 @@ export class MemberCipherDetailsApiService {
true,
);
const listResponse = new ListResponse(response, MemberCipherDetailsResponse);
return listResponse.data.map((r) => new MemberCipherDetailsResponse(r));
return response;
}
}

View File

@@ -3,15 +3,17 @@ import { TestBed } from "@angular/core/testing";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { mockCiphers } from "./ciphers.mock";
import { MemberCipherDetailsApiService } from "./member-cipher-details-api.service";
import { mockMemberCipherDetails } from "./member-cipher-details-api.service.spec";
import { PasswordHealthService } from "./password-health.service";
describe("PasswordHealthService", () => {
let service: PasswordHealthService;
let cipherService: CipherService;
let memberCipherDetailsApiService: MemberCipherDetailsApiService;
beforeEach(() => {
TestBed.configureTestingModule({
@@ -35,7 +37,13 @@ describe("PasswordHealthService", () => {
{
provide: CipherService,
useValue: {
getAllFromApiForOrganization: jest.fn().mockResolvedValue(CipherData),
getAllFromApiForOrganization: jest.fn().mockResolvedValue(mockCiphers),
},
},
{
provide: MemberCipherDetailsApiService,
useValue: {
getMemberCipherDetails: jest.fn().mockResolvedValue(mockMemberCipherDetails),
},
},
{ provide: "organizationId", useValue: "org1" },
@@ -44,6 +52,7 @@ describe("PasswordHealthService", () => {
service = TestBed.inject(PasswordHealthService);
cipherService = TestBed.inject(CipherService);
memberCipherDetailsApiService = TestBed.inject(MemberCipherDetailsApiService);
});
it("should be created", () => {
@@ -68,6 +77,10 @@ describe("PasswordHealthService", () => {
expect(cipherService.getAllFromApiForOrganization).toHaveBeenCalledWith("org1");
});
it("should fetch member cipher details", () => {
expect(memberCipherDetailsApiService.getMemberCipherDetails).toHaveBeenCalledWith("org1");
});
it("should populate reportCiphers with ciphers that have issues", () => {
expect(service.reportCiphers.length).toBeGreaterThan(0);
});
@@ -99,12 +112,12 @@ describe("PasswordHealthService", () => {
it("should calculate total members per cipher", () => {
expect(service.totalMembersMap.size).toBeGreaterThan(0);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228ab1")).toBe(3);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228ab2")).toBe(5);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228cd3")).toBe(6);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228ab1")).toBe(2);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228ab2")).toBe(4);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228cd3")).toBe(5);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001227nm5")).toBe(4);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001227nm7")).toBe(1);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228xy4")).toBe(7);
expect(service.totalMembersMap.get("cbea34a8-bde4-46ad-9d19-b05001228xy4")).toBe(6);
});
});

View File

@@ -1,9 +1,5 @@
import { Inject, Injectable } from "@angular/core";
// eslint-disable-next-line no-restricted-imports
import { mockCiphers } from "@bitwarden/bit-common/tools/reports/risk-insights/services/ciphers.mock";
// eslint-disable-next-line no-restricted-imports
import { mockMemberCipherDetailsResponse } from "@bitwarden/bit-common/tools/reports/risk-insights/services/member-cipher-details-response.mock";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
@@ -12,6 +8,8 @@ import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { BadgeVariant } from "@bitwarden/components";
import { MemberCipherDetailsApiService } from "./member-cipher-details-api.service";
@Injectable()
export class PasswordHealthService {
reportCiphers: CipherView[] = [];
@@ -30,21 +28,23 @@ export class PasswordHealthService {
private passwordStrengthService: PasswordStrengthServiceAbstraction,
private auditService: AuditService,
private cipherService: CipherService,
private memberCipherDetailsApiService: MemberCipherDetailsApiService,
@Inject("organizationId") private organizationId: string,
) {}
async generateReport() {
let allCiphers = await this.cipherService.getAllFromApiForOrganization(this.organizationId);
// TODO remove when actual user member data is available
allCiphers = mockCiphers;
const allCiphers = await this.cipherService.getAllFromApiForOrganization(this.organizationId);
allCiphers.forEach(async (cipher) => {
this.findWeakPassword(cipher);
this.findReusedPassword(cipher);
await this.findExposedPassword(cipher);
});
// TODO - fetch actual user member when data is available
mockMemberCipherDetailsResponse.data.forEach((user) => {
const memberCipherDetails = await this.memberCipherDetailsApiService.getMemberCipherDetails(
this.organizationId,
);
memberCipherDetails.forEach((user) => {
user.cipherIds.forEach((cipherId: string) => {
if (this.totalMembersMap.has(cipherId)) {
this.totalMembersMap.set(cipherId, (this.totalMembersMap.get(cipherId) || 0) + 1);