From 2fd8c8b8b7ead129c69a4d9208ff66898e1d9a66 Mon Sep 17 00:00:00 2001 From: Tom <144813356+ttalty@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:07:28 -0400 Subject: [PATCH] [PM-13402] Adding the service to get member cipher details (#11544) * Adding the service to get member cipher details * Moving member cipher details to bitwarden license * Adding documentation to the api call --- .../reports/access-intelligence/index.ts | 0 .../member-cipher-details.response.ts | 16 +++ .../member-cipher-details-api.service.spec.ts | 105 ++++++++++++++++++ .../member-cipher-details-api.service.ts | 27 +++++ 4 files changed, 148 insertions(+) create mode 100644 bitwarden_license/bit-common/src/tools/reports/access-intelligence/index.ts create mode 100644 bitwarden_license/bit-common/src/tools/reports/access-intelligence/response/member-cipher-details.response.ts create mode 100644 bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.spec.ts create mode 100644 bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.ts diff --git a/bitwarden_license/bit-common/src/tools/reports/access-intelligence/index.ts b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bitwarden_license/bit-common/src/tools/reports/access-intelligence/response/member-cipher-details.response.ts b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/response/member-cipher-details.response.ts new file mode 100644 index 0000000000..fcf5ada4b2 --- /dev/null +++ b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/response/member-cipher-details.response.ts @@ -0,0 +1,16 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +export class MemberCipherDetailsResponse extends BaseResponse { + userName: string; + email: string; + useKeyConnector: boolean; + cipherIds: string[] = []; + + constructor(response: any) { + super(response); + this.userName = this.getResponseProperty("UserName"); + this.email = this.getResponseProperty("Email"); + this.useKeyConnector = this.getResponseProperty("UseKeyConnector"); + this.cipherIds = this.getResponseProperty("CipherIds"); + } +} diff --git a/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.spec.ts b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.spec.ts new file mode 100644 index 0000000000..b71abe075e --- /dev/null +++ b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.spec.ts @@ -0,0 +1,105 @@ +import { mock } from "jest-mock-extended"; + +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", + ], + }, + ], +}; + +describe("Member Cipher Details API Service", () => { + let memberCipherDetailsApiService: MemberCipherDetailsApiService; + + const apiService = mock(); + + beforeEach(() => { + memberCipherDetailsApiService = new MemberCipherDetailsApiService(apiService); + jest.resetAllMocks(); + }); + + it("instantiates", () => { + expect(memberCipherDetailsApiService).not.toBeFalsy(); + }); + + it("getMemberCipherDetails retrieves data", async () => { + apiService.send.mockResolvedValue(mockMemberCipherDetails); + + const orgId = "1234"; + const result = await memberCipherDetailsApiService.getMemberCipherDetails(orgId); + expect(result).not.toBeNull(); + expect(result).toHaveLength(6); + expect(apiService.send).toHaveBeenCalledWith( + "GET", + "/reports/member-cipher-details/" + orgId, + null, + true, + true, + ); + }); +}); diff --git a/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.ts b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.ts new file mode 100644 index 0000000000..9351ac8777 --- /dev/null +++ b/bitwarden_license/bit-common/src/tools/reports/access-intelligence/services/member-cipher-details-api.service.ts @@ -0,0 +1,27 @@ +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"; + +export class MemberCipherDetailsApiService { + constructor(private apiService: ApiService) {} + + /** + * Returns a list of organization members with their assigned + * cipherIds + * @param orgId OrganizationId to get member cipher details for + * @returns List of organization members and assigned cipherIds + */ + async getMemberCipherDetails(orgId: string): Promise { + const response = await this.apiService.send( + "GET", + "/reports/member-cipher-details/" + orgId, + null, + true, + true, + ); + + const listResponse = new ListResponse(response, MemberCipherDetailsResponse); + return listResponse.data.map((r) => new MemberCipherDetailsResponse(r)); + } +}