Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
22 KiB
@suaveplan/hibp - Privacy-preserving Have I Been Pwned v3 client — k-anonymity range API, authenticated breach/paste API, LRU cache, differential-privacy mode
Summary
Privacy-preserving Have I Been Pwned v3 client.
Universal — works in Node, Bun, Deno, browsers, edge workers. The only
required runtime primitive is fetch.
Documentation tree
- breach-client —
BreachClientwraps the four authenticated HIBP v3 endpoints:/breachedaccount/{email},/breach/{name}, `/breaches… - rate-limit-gate —
RateLimitGateenforces the HIBP v3 client-side rate-limit contract of one request per 1500 ms across the authenticate… - retry-after —
parseRetryAfterparses theRetry-AfterHTTP header per RFC 9110 §10.2.3 and returns the indicated delay in millisec… - cache — (no submodules) - lru —
LruHibpCache<V>is the default cache for `H…- cache — (no submodules) - lru —
LruHibpCache<V>is the default cache for `H… - lru —
LruHibpCache<V>is the default cache forHibpClient. It holds up toLRU_DEFAULT_CAPACITYentries (10 000) with `L… - null —
NullHibpCache<V>is the always-miss adapter used byHibpClientwhen the caller explicitly opts out of caching (`cac…
- cache — (no submodules) - lru —
- client — (no submodules) - options.schema —
HibpClientOptionsSchemais the Z…- client — (no submodules) - options.schema —
HibpClientOptionsSchemais the Z… - options.schema —
HibpClientOptionsSchemais the Zod boundary for theHibpClientconstructor. It is.strict()— unknown keys cause…
- client — (no submodules) - options.schema —
- codes — Spec-canonical path for the HIBP error-code registry. This file is a thin re-export of the top-level `src/error-codes.t…
- hibp-error —
HibpErroris the structured error class every failure path inside@suaveplan/hibpthrows. It carries one of the sev… - observability — (no submodules)
- metrics — (no submodules)
- privacy — (no submodules)
- assert-no-leak — (no submodules)
- range — (no submodules)
- constant-time-compare —
constantTimeEqualsHexcompares two hex suffixes without early-exit on the first mismatching character. It is used by… - differential-privacy —
padPrefixesgenerates the decoy prefixes used by the differential-privacy mode ofcheckPassword. Given the real 5-h… - range-mode — Houses the hash-mode dispatch utilities used by
checkPassword:hashSha1Prefix(SHA-1 via@noble/hashes/sha1), `ha… - range-stream-parse — Streams an HTTP response body line-by-line through a
TextDecoderStreamand a newline framer, yielding `{ suffix, coun… - range-strict-frame —
parseRangeLineis the per-line framer used bystreamParseRangeBody. It enforces the documented Pwned Passwords line… - range — (no submodules)
- constant-time-compare —
- breach.schema —
BreachSchemais the Zod schema mirroring the HIBP v3Breachpayload. It validates every documented field, so the re… - paste.schema —
PasteSchemavalidates the HIBP v3Pastepayload returned by/pasteaccount/{email}. Older paste records can omit `… - pwned-result.schema —
PwnedResultSchemavalidates the runtime shape of everycheckPasswordresult. It is the final boundary between the i… - error-codes — Hosts the canonical
HIBP_CODESregistry — exactly seven error codes that classify every failure path inside `@suavepl…
-
cache — (no submodules)- lru —
LruHibpCache<V>is the default cache for `H… -
lru —
LruHibpCache<V>is the default cache forHibpClient. It holds up toLRU_DEFAULT_CAPACITYentries (10 000) with `L… -
null —
NullHibpCache<V>is the always-miss adapter used byHibpClientwhen the caller explicitly opts out of caching (`cac… -
client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z…- client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z… - options.schema —
HibpClientOptionsSchemais the Zod boundary for theHibpClientconstructor. It is.strict()— unknown keys cause…
- client — (no submodules)- options.schema —
-
codes — Spec-canonical path for the HIBP error-code registry. This file is a thin re-export of the top-level `src/error-codes.t…
-
hibp-error —
HibpErroris the structured error class every failure path inside@suaveplan/hibpthrows. It carries one of the sev… -
observability — (no submodules)- metrics — (no submodules)- privacy — (no submodules)- assert-no-leak — (no submodules)- range — (no submodules)- constant-time-compare —
constantTimeEqualsHexcompares two hex suffixes without early-exit on the first mismatching character. It is used by…- differential-privacy —
padPrefixesgenerates the decoy prefixes used by the differential-privacy mode ofcheckPassword. Given the real 5-h… - range-mode — Houses the hash-mode dispatch utilities used by
checkPassword:hashSha1Prefix(SHA-1 via@noble/hashes/sha1), `ha… - range-stream-parse — Streams an HTTP response body line-by-line through a
TextDecoderStreamand a newline framer, yielding `{ suffix, coun… - range-strict-frame —
parseRangeLineis the per-line framer used bystreamParseRangeBody. It enforces the documented Pwned Passwords line… - range — (no submodules)- breach.schema —
BreachSchemais the Zod schema mirroring the HIBP v3Breachpayload. It validates every documented field, so the re…
- differential-privacy —
-
paste.schema —
PasteSchemavalidates the HIBP v3Pastepayload returned by/pasteaccount/{email}. Older paste records can omit `… -
pwned-result.schema —
PwnedResultSchemavalidates the runtime shape of everycheckPasswordresult. It is the final boundary between the i… -
error-codes — Hosts the canonical
HIBP_CODESregistry — exactly seven error codes that classify every failure path inside `@suavepl… -
lru —
LruHibpCache<V>is the default cache for `H… -
cache — (no submodules)- lru —
LruHibpCache<V>is the default cache for `H… -
lru —
LruHibpCache<V>is the default cache forHibpClient. It holds up toLRU_DEFAULT_CAPACITYentries (10 000) with `L… -
null —
NullHibpCache<V>is the always-miss adapter used byHibpClientwhen the caller explicitly opts out of caching (`cac… -
client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z…- client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z… - options.schema —
HibpClientOptionsSchemais the Zod boundary for theHibpClientconstructor. It is.strict()— unknown keys cause…
- client — (no submodules)- options.schema —
-
codes — Spec-canonical path for the HIBP error-code registry. This file is a thin re-export of the top-level `src/error-codes.t…
-
hibp-error —
HibpErroris the structured error class every failure path inside@suaveplan/hibpthrows. It carries one of the sev… -
observability — (no submodules)- metrics — (no submodules)- privacy — (no submodules)- assert-no-leak — (no submodules)- range — (no submodules)- constant-time-compare —
constantTimeEqualsHexcompares two hex suffixes without early-exit on the first mismatching character. It is used by…- differential-privacy —
padPrefixesgenerates the decoy prefixes used by the differential-privacy mode ofcheckPassword. Given the real 5-h… - range-mode — Houses the hash-mode dispatch utilities used by
checkPassword:hashSha1Prefix(SHA-1 via@noble/hashes/sha1), `ha… - range-stream-parse — Streams an HTTP response body line-by-line through a
TextDecoderStreamand a newline framer, yielding `{ suffix, coun… - range-strict-frame —
parseRangeLineis the per-line framer used bystreamParseRangeBody. It enforces the documented Pwned Passwords line… - range — (no submodules)- breach.schema —
BreachSchemais the Zod schema mirroring the HIBP v3Breachpayload. It validates every documented field, so the re…
- differential-privacy —
-
paste.schema —
PasteSchemavalidates the HIBP v3Pastepayload returned by/pasteaccount/{email}. Older paste records can omit `… -
pwned-result.schema —
PwnedResultSchemavalidates the runtime shape of everycheckPasswordresult. It is the final boundary between the i… -
error-codes — Hosts the canonical
HIBP_CODESregistry — exactly seven error codes that classify every failure path inside `@suavepl… -
lru —
LruHibpCache<V>is the default cache for `H… -
cache — (no submodules)- lru —
LruHibpCache<V>is the default cache for `H… -
lru —
LruHibpCache<V>is the default cache forHibpClient. It holds up toLRU_DEFAULT_CAPACITYentries (10 000) with `L… -
null —
NullHibpCache<V>is the always-miss adapter used byHibpClientwhen the caller explicitly opts out of caching (`cac… -
client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z…- client — (no submodules)- options.schema —
HibpClientOptionsSchemais the Z… - options.schema —
HibpClientOptionsSchemais the Zod boundary for theHibpClientconstructor. It is.strict()— unknown keys cause…
- client — (no submodules)- options.schema —
-
codes — Spec-canonical path for the HIBP error-code registry. This file is a thin re-export of the top-level `src/error-codes.t…
-
hibp-error —
HibpErroris the structured error class every failure path inside@suaveplan/hibpthrows. It carries one of the sev… -
observability — (no submodules)- metrics — (no submodules)- privacy — (no submodules)- assert-no-leak — (no submodules)- range — (no submodules)- constant-time-compare —
constantTimeEqualsHexcompares two hex suffixes without early-exit on the first mismatching character. It is used by…- differential-privacy —
padPrefixesgenerates the decoy prefixes used by the differential-privacy mode ofcheckPassword. Given the real 5-h… - range-mode — Houses the hash-mode dispatch utilities used by
checkPassword:hashSha1Prefix(SHA-1 via@noble/hashes/sha1), `ha… - range-stream-parse — Streams an HTTP response body line-by-line through a
TextDecoderStreamand a newline framer, yielding `{ suffix, coun… - range-strict-frame —
parseRangeLineis the per-line framer used bystreamParseRangeBody. It enforces the documented Pwned Passwords line… - range — (no submodules)- breach.schema —
BreachSchemais the Zod schema mirroring the HIBP v3Breachpayload. It validates every documented field, so the re…
- differential-privacy —
-
paste.schema —
PasteSchemavalidates the HIBP v3Pastepayload returned by/pasteaccount/{email}. Older paste records can omit `… -
pwned-result.schema —
PwnedResultSchemavalidates the runtime shape of everycheckPasswordresult. It is the final boundary between the i… -
error-codes — Hosts the canonical
HIBP_CODESregistry — exactly seven error codes that classify every failure path inside `@suavepl… -
cache — (no submodules)- lru —
LruHibpCache<V>is the default cache forHibpClient. It holds up toLRU_DEFAULT_CAPACITYentries (10 000) with `L… -
null —
NullHibpCache<V>is the always-miss adapter used byHibpClientwhen the caller explicitly opts out of caching (`cac… -
client — (no submodules) - client — (no submodules) - options.schema —
HibpClientOptionsSchemais the Zod boundary for theHibpClientconstructor. It is.strict()— unknown keys cause… -
codes — Spec-canonical path for the HIBP error-code registry. This file is a thin re-export of the top-level `src/error-codes.t…
-
hibp-error —
HibpErroris the structured error class every failure path inside@suaveplan/hibpthrows. It carries one of the sev… -
observability — (no submodules) - metrics — (no submodules)- privacy — (no submodules) - assert-no-leak — (no submodules)- range — (no submodules) - constant-time-compare —
constantTimeEqualsHexcompares two hex suffixes without early-exit on the first mismatching character. It is used by…- differential-privacy —
padPrefixesgenerates the decoy prefixes used by the differential-privacy mode ofcheckPassword. Given the real 5-h… - range-mode — Houses the hash-mode dispatch utilities used by
checkPassword:hashSha1Prefix(SHA-1 via@noble/hashes/sha1), `ha… - range-stream-parse — Streams an HTTP response body line-by-line through a
TextDecoderStreamand a newline framer, yielding `{ suffix, coun… - range-strict-frame —
parseRangeLineis the per-line framer used bystreamParseRangeBody. It enforces the documented Pwned Passwords line… - range — (no submodules)- breach.schema —
BreachSchemais the Zod schema mirroring the HIBP v3Breachpayload. It…
- differential-privacy —
-
paste.schema —
PasteSchemavalidates the HIBP v3Pastepayload returned by `… -
pwned-result.schema —
PwnedResultSchemavalidates the runtime shape of everycheckPasswordresult. It is the final boundary between the i… -
error-codes — Hosts the canonical
HIBP_CODESregistry — exactly seven error codes that classify every failure path inside `@suavepl…
Privacy contract
This package treats the password and its SHA-1 digest as secrets that must never leave the calling process.
- Only the first five hex characters of the SHA-1 digest are transmitted to the Pwned Passwords range API (k-anonymity).
- Every range request carries the mandatory
Add-Padding: trueheader so Cloudflare appends decoy lines, defeating response-size correlation attacks. - The full password, the full hash, the API key, and the email are never logged and never appear in any thrown error's serialized form.
- An opt-in
assertOutgoingRequestSafe: trueswitch wraps every outgoing fetch with a byte-by-byte leak check so callers can catch a regression before it lands in production.
If any of those invariants ever break, that is a defect, not a feature request.
Install
bun add @suaveplan/hibp
Quick start
Check a single password against the range API
import { HibpClient } from "@suaveplan/hibp";
const client = new HibpClient();
const result = await client.checkPassword("hunter2");
// { pwned: true, count: 23_597 }
Pull the breach list for an account
import { HibpClient } from "@suaveplan/hibp";
const client = new HibpClient({ apiKey: process.env.HIBP_API_KEY! });
const breaches = await client.getBreachesForAccount("user@example.com");
// Breach[]
Differential-privacy mode
For deployments that want belt-and-braces defence on top of the standard
Add-Padding padding, opt in to decoy prefixes. Every checkPassword call
will dispatch the real 5-hex prefix plus N additional random sibling
prefixes; only the real one's response is consulted.
const client = new HibpClient({
differentialPrivacy: { extraPrefixes: 3 },
rng: myInjectableRng,
});
Trade-offs:
- Adds N extra round trips per check. Default off because the
Add-Paddingheader already defeats the documented correlation attack for almost every deployment. - Decoy responses are discarded but still count against any caching
layer's bandwidth budget. Tune
extraPrefixesto match the operational cost.
Modules
| Path | Purpose |
|---|---|
src/client/client.md |
HibpClient façade orchestrating range + breach + cache + observability |
src/client/options.schema.md |
Zod boundary for constructor options |
src/range/range.md |
k-anonymity range API client |
src/range/range-mode.md |
SHA-1 / NTLM mode dispatch |
src/range/range-stream-parse.md |
Streaming line parser |
src/range/range-strict-frame.md |
Strict-mode line framing |
src/range/constant-time-compare.md |
Constant-time suffix compare |
src/range/differential-privacy.md |
Decoy prefix generator |
src/breach/breach-client.md |
Authenticated breach + paste API client |
src/breach/rate-limit-gate.md |
1500 ms client-side rate-limit gate |
src/breach/retry-after.md |
RFC 9110 Retry-After parser |
src/cache/cache.md |
HibpCacheLike interface |
src/cache/lru.md |
Default LRU cache (10 000 / 24 h) |
src/cache/null.md |
Always-miss cache adapter |
src/errors/codes.md |
Seven-code error registry |
src/errors/hibp-error.md |
HibpError base class |
src/error-codes.md |
Top-level code registration |
src/observability/metrics.md |
OTel histograms + counters |
src/privacy/assert-no-leak.md |
Outgoing-request leak detector |
src/schemas/breach.schema.md |
BreachSchema Zod schema |
src/schemas/paste.schema.md |
PasteSchema Zod schema |
src/schemas/pwned-result.schema.md |
PwnedResultSchema Zod schema |
Benchmarks
| Benchmark | Description |
|---|---|
range-cold |
Cold range fetch + parse |
range-warm-cache |
LRU hit path |
range-parse-30kib |
Streaming parser throughput on a 30 KiB padded fixture |
Run with bun run benchmark (see src/__benchmarks__/).
License
MIT