Files
skills/docs/security-stack/security/hibp/src/range/range.md
2026-05-29 08:20:56 +01:00

2.8 KiB

range/range.ts

(no submodules)

Purpose

RangeClient is the heart of the package — the k-anonymity Pwned Passwords client. checkPassword(password, opts?) hashes the input, slices the 5-hex prefix, dispatches GET https://api.pwnedpasswords.com/range/<prefix> with the mandatory Add-Padding: true header, scans the streamed response for a matching 35-char suffix, and returns { pwned, count }. It owns the strict / off framing, the NTLM mode opt-in, the differential-privacy decoy fan-out, the AbortSignal threading, and the OTel emission.

Features

  • Mandatory Add-Padding: true on every fetch — including every differential-privacy decoy.
  • SHA-1 (default) and NTLM (caller-injected adapter) hash modes.
  • Constant-time suffix compare on every parsed line.
  • Streaming line parser (no Response.text() call ever).
  • Differential-privacy decoy fan-out when extraPrefixes > 0 — real prefix's response is the only one consulted.
  • AbortSignal threaded into fetch and the streaming parser.
  • OTel histograms for duration; counters for outcome, errors, throttling.
  • Optional assertOutgoingRequestSafe: true runtime privacy gate.

Usage: Basic Example

import { RangeClient } from "@suaveplan/hibp";

const client = new RangeClient();
const { pwned, count } = await client.checkPassword("hunter2");

Usage: Advanced Example

import { RangeClient } from "@suaveplan/hibp";

const client = new RangeClient({
    extraPrefixes: 3,
    rng: myRng,
    assertOutgoingRequestSafe: true,
    strict: true,
});

const ac = new AbortController();
setTimeout(() => ac.abort(), 5_000);
const result = await client.checkPassword("hunter2", { signal: ac.signal });

API Reference

  • CheckPasswordOptions — mode?, signal?, extraPrefixes?.
  • RangeClientOptions — fetchFn, clock, rng, strict, ntlmHash, extraPrefixes, assertOutgoingRequestSafe.
  • new RangeClient(options?).
  • client.checkPassword(password, opts?): Promise<PwnedResult>.

Implementation Notes

The class is stateless beyond its constructor options — every public method takes the password and a per-call options bag, so a single RangeClient instance is safe to share across a process. Error paths funnel through the metrics emission so dashboards see counters even for failures the caller catches and retries. The assertOutgoingRequestSafe gate constructs a Request to feed into assertNoLeak, then re-issues the actual fetch with the same RequestInit so the privacy check exercises the real outgoing bytes. The NTLM adapter is required at runtime if mode: "ntlm" is ever passed; a missing adapter surfaces as HIBP.MALFORMED_RESPONSE because the caller has misconfigured the client rather than the server having misbehaved.