1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-08 03:23:50 +00:00

[PM-25417] DIRT API Service Refactor (ADR-0005) (#16353)

* encode username for uri and add spec

* verify response from getHibpBreach method

* test/validate for BreachAccountResponse type and length instead of mock response

* - extract dirt api method out of global api service
- create new directory structure
- change imports accordingly
- extract breach account response
- put extracted code into new dirt dir

* codeowners and dep injection for new hibp service
This commit is contained in:
Alex
2025-09-22 10:06:58 -04:00
committed by GitHub
parent 3a721b535c
commit 8531109081
21 changed files with 132 additions and 48 deletions

View File

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

View File

@@ -0,0 +1 @@
export * from "./response";

View File

@@ -0,0 +1,32 @@
import { BaseResponse } from "../../../models/response/base.response";
export class BreachAccountResponse extends BaseResponse {
addedDate: string;
breachDate: string;
dataClasses: string[];
description: string;
domain: string;
isActive: boolean;
isVerified: boolean;
logoPath: string;
modifiedDate: string;
name: string;
pwnCount: number;
title: string;
constructor(response: any) {
super(response);
this.addedDate = this.getResponseProperty("AddedDate");
this.breachDate = this.getResponseProperty("BreachDate");
this.dataClasses = this.getResponseProperty("DataClasses");
this.description = this.getResponseProperty("Description");
this.domain = this.getResponseProperty("Domain");
this.isActive = this.getResponseProperty("IsActive");
this.isVerified = this.getResponseProperty("IsVerified");
this.logoPath = this.getResponseProperty("LogoPath");
this.modifiedDate = this.getResponseProperty("ModifiedDate");
this.name = this.getResponseProperty("Name");
this.pwnCount = this.getResponseProperty("PwnCount");
this.title = this.getResponseProperty("Title");
}
}

View File

@@ -0,0 +1 @@
export * from "./breach-account.response";

View File

@@ -0,0 +1,20 @@
import { ApiService } from "../../abstractions/api.service";
import { DirtApiService } from "./dirt-api.service";
describe("DirtApiService", () => {
let sut: DirtApiService;
let apiService: jest.Mocked<ApiService>;
beforeEach(() => {
apiService = {
send: jest.fn(),
} as any;
sut = new DirtApiService(apiService);
});
it("should be created", () => {
expect(sut).toBeTruthy();
});
});

View File

@@ -0,0 +1,8 @@
import { ApiService } from "../../abstractions/api.service";
export class DirtApiService {
constructor(private apiService: ApiService) {}
// This service can be used for general DIRT-related API methods
// For specific domains like HIBP, use dedicated services like HibpApiService
}

View File

@@ -0,0 +1,39 @@
import { ApiService } from "../../abstractions/api.service";
import { BreachAccountResponse } from "../models";
import { HibpApiService } from "./hibp-api.service";
describe("HibpApiService", () => {
let sut: HibpApiService;
let apiService: jest.Mocked<ApiService>;
beforeEach(() => {
apiService = {
send: jest.fn(),
} as any;
sut = new HibpApiService(apiService);
});
describe("getHibpBreach", () => {
it("should properly URL encode username with special characters", async () => {
const mockResponse = [{ name: "test" }];
const username = "connect#bwpm@simplelogin.co";
apiService.send.mockResolvedValue(mockResponse);
const result = await sut.getHibpBreach(username);
expect(apiService.send).toHaveBeenCalledWith(
"GET",
"/hibp/breach?username=" + encodeURIComponent(username),
null,
true,
true,
);
expect(result).toBeInstanceOf(Array);
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(BreachAccountResponse);
});
});
});

View File

@@ -0,0 +1,18 @@
import { ApiService } from "../../abstractions/api.service";
import { BreachAccountResponse } from "../models";
export class HibpApiService {
constructor(private apiService: ApiService) {}
async getHibpBreach(username: string): Promise<BreachAccountResponse[]> {
const encodedUsername = encodeURIComponent(username);
const r = await this.apiService.send(
"GET",
"/hibp/breach?username=" + encodedUsername,
null,
true,
true,
);
return r.map((a: any) => new BreachAccountResponse(a));
}
}

View File

@@ -0,0 +1,2 @@
export * from "./dirt-api.service";
export * from "./hibp-api.service";