first commit
This commit is contained in:
60
docs/security-stack/security/hibp/src/range/range-mode.md
Normal file
60
docs/security-stack/security/hibp/src/range/range-mode.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# `range/range-mode.ts`
|
||||
|
||||
## Purpose
|
||||
|
||||
Houses the hash-mode dispatch utilities used by `checkPassword`:
|
||||
`hashSha1Prefix` (SHA-1 via `@noble/hashes/sha1`), `hashNtlmPrefix`
|
||||
(MD4-over-UTF-16-LE, supplied by an injectable adapter because not every
|
||||
runtime ships an MD4 implementation), and `buildRangeUrl` (assembles the
|
||||
final `/range/<prefix>[?mode=ntlm]` URL). The split between hashing and
|
||||
URL building keeps each function small, testable, and reusable from
|
||||
both the public `checkPassword` path and the privacy-leak verification
|
||||
helpers.
|
||||
|
||||
## Features
|
||||
|
||||
- `hashSha1Prefix(password)` returns `{ prefix, suffix, full }` with the
|
||||
uppercase 40-char digest and its k-anonymity decomposition.
|
||||
- `hashNtlmPrefix(password, adapter)` accepts a caller-supplied adapter,
|
||||
validating that the returned digest is exactly 40 uppercase hex chars.
|
||||
- `buildRangeUrl(prefix, mode)` appends `?mode=ntlm` only when the mode
|
||||
is `"ntlm"` — SHA-1 mode never sends a query string.
|
||||
- `RangeMode` type alias narrows callers to the two valid values.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { buildRangeUrl, hashSha1Prefix } from "@suaveplan/hibp";
|
||||
|
||||
const { prefix } = hashSha1Prefix("hunter2");
|
||||
const url = buildRangeUrl(prefix, "sha1");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { buildRangeUrl, hashNtlmPrefix } from "@suaveplan/hibp";
|
||||
import { md4 } from "my-ntlm-adapter";
|
||||
|
||||
const { prefix } = hashNtlmPrefix("hunter2", (pw) => md4(pw).toUpperCase());
|
||||
const url = buildRangeUrl(prefix, "ntlm");
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `RangeMode = "sha1" | "ntlm"`.
|
||||
- `NtlmHashAdapter = (password: string) => string`.
|
||||
- `hashSha1Prefix(password): { prefix, suffix, full }`.
|
||||
- `hashNtlmPrefix(password, adapter): { prefix, suffix, full }`.
|
||||
- `buildRangeUrl(prefix, mode): string`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
SHA-1 is sourced from `@noble/hashes/sha1` rather than from
|
||||
`@suaveplan/crypto-hash` because the crypto-hash package deliberately
|
||||
omits SHA-1 (collision-broken for security purposes). The HIBP API
|
||||
requires SHA-1 strictly for k-anonymity bucket selection — never for
|
||||
security — so the direct noble dependency is the right call.
|
||||
`hashNtlmPrefix` validates the adapter output rather than trusting it
|
||||
because a buggy adapter could produce shorter strings and accidentally
|
||||
leak unrelated bytes.
|
||||
Reference in New Issue
Block a user