vault.hibp-padding.test.ts

2.6 KB · raw

1// PCH-02-007 regression tests — the HIBP k-anonymity range request must ask2// for response padding, and the parser must stay correct on padded responses.3//4// DESTINATION: src/background/vault.hibp-padding.test.ts5// Imports are written in destination form; this file is excluded from the6// suite while it lives under src/drafts/.78import { beforeEach, describe, expect, it, vi } from "vitest";910// SHA-1("password") = 5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD811const PREFIX = "5BAA6";12const SUFFIX = "1E4C9B93F3F0682250B6CF8331B7EE68FD8";1314describe("PCH-02-007 — HIBP Add-Padding", () => {15  let fetchMock: ReturnType<typeof vi.fn>;1617  beforeEach(() => {18    vi.resetModules();1920    const chromeMock = {21      storage: {22        local: {23          get: vi.fn(async () => ({})),24          set: vi.fn(async () => undefined),25          remove: vi.fn(async () => undefined),26        },27      },28      alarms: {29        clear: vi.fn(),30        create: vi.fn(),31        onAlarm: { addListener: vi.fn() },32      },33      idle: {34        setDetectionInterval: vi.fn(),35        onStateChanged: { addListener: vi.fn() },36      },37    } as unknown as typeof chrome;38    (globalThis as { chrome?: typeof chrome }).chrome = chromeMock;3940    fetchMock = vi.fn(async () => ({41      ok: true,42      text: async () =>43        [44          "0018A45C4D1DEF81644B54AB7F969B88D65:1",45          `${SUFFIX}:3303003`,46          // Padding lines HIBP appends under Add-Padding — always count 0.47          "FFFFFFAAAAAABBBBBBCCCCCCDDDDDDEEEEE:0",48        ].join("\r\n"),49    }));50    vi.stubGlobal("fetch", fetchMock);51  });5253  it("sends Add-Padding: true on the range request", async () => {54    const vault = await import("./vault");55    await vault.checkBreach("password");5657    expect(fetchMock).toHaveBeenCalledWith(58      `https://api.pwnedpasswords.com/range/${PREFIX}`,59      expect.objectContaining({60        headers: expect.objectContaining({ "Add-Padding": "true" }),61      }),62    );63  });6465  it("still parses the real breach count out of a padded response", async () => {66    const vault = await import("./vault");67    const count = await vault.checkBreach("password");68    expect(count).toBe(3303003);69  });7071  it("reports 0 when the response holds only padding lines", async () => {72    fetchMock.mockImplementationOnce(async () => ({73      ok: true,74      text: async () =>75        [76          "FFFFFFAAAAAABBBBBBCCCCCCDDDDDDEEEEE:0",77          "EEEEEEAAAAAABBBBBBCCCCCCDDDDDDFFFFF:0",78        ].join("\r\n"),79    }));8081    const vault = await import("./vault");82    const count = await vault.checkBreach("password");83    expect(count).toBe(0);84  });85});