Files
suaveplan/packages/security-stack/security/password-strength/src/matchers/sequence/sequence.md
2026-05-27 23:47:53 +01:00

2.6 KiB

sequence — alphanumeric sequence matcher

(no submodules)

Purpose

Detects ascending and descending runs of consecutive characters within a single alphabet class (lowercase letters, uppercase letters, decimal digits) per Wheeler §3.2. A run of abcd carries far less entropy than four random letters and the scorer needs an explicit pattern record to compute the right guesses count.

Features

  • Lower, upper, and digit alphabets
  • Both directions (ascending 1234, descending 9876)
  • Minimum length 2
  • Each match carries sequenceSpace (size of the alphabet) and ascending

Usage: Basic Example

import { sequenceMatch } from "@suaveplan/password-strength/matchers/sequence";

const matches = sequenceMatch("abcd");
console.log(matches[0].ascending); // true
console.log(matches[0].sequenceName); // "lower"

Usage: Advanced Example

import { sequenceMatch } from "@suaveplan/password-strength/matchers/sequence";

// Mixed runs are reported separately
for (const m of sequenceMatch("abc987XYZ")) {
 console.log(m.token, m.sequenceName, m.ascending);
}
// abc lower true
// 987 digits false
// XYZ upper true

API Reference

  • sequenceMatch(password: string): SequenceMatch[] — return every maximal ascending or descending run of length ≥ 2 within a single alphabet class.

Implementation Notes

The walk is single-pass: at each index, the matcher checks the delta between adjacent characters; if it is +1 or -1 within the same alphabet, the matcher extends the run greedily until the delta breaks or the alphabet changes. Runs of length 1 are filtered out. The algorithm is O(n) over the password length and emits each maximal run exactly once.

Additional Implementation Notes

The implementation follows the canonical zxcvbn algorithm from Wheeler 2016 with the suaveplan-style additions described in the package proposal: structured error codes via the defineCodes registry, Zod boundaries at every public entry point, OTel histograms and counters keyed to low-cardinality attributes, and a strict input-length guard at 200 characters. Consumers integrate with their existing observability stack by installing a meter provider before importing the package, and with their i18n stack via the MessageResolver callback type declared in @suaveplan/types. The bundled data tables are intentionally small to keep the package bundle compact; production deployments should swap in fuller frequency-ranked tables via loadDictionaries. The default English dictionary set is a frozen DictionarySet that the matcher never mutates; caller-supplied dictionaries override defaults by name.