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

2.2 KiB

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

import { buildRangeUrl, hashSha1Prefix } from "@suaveplan/hibp";

const { prefix } = hashSha1Prefix("hunter2");
const url = buildRangeUrl(prefix, "sha1");

Usage: Advanced Example

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.