208 lines
34 KiB
Markdown
208 lines
34 KiB
Markdown
# @suaveplan/password-strength - zxcvbn-style password strength estimator — pattern-matching + dictionary cracker model per Wheeler 2016. Zero browser/Node/React deps.
|
||
|
||
## Summary
|
||
|
||
zxcvbn-style password strength estimator — pattern-matching + dictionary
|
||
cracker model per Wheeler 2016. Universal; zero browser/Node/React
|
||
deps. Re-implementation of the open-source `dropbox/zxcvbn` algorithm in
|
||
style: Zod boundaries, OTel histograms + counters, structured
|
||
`PWSTRENGTH.*` error codes, 100% coverage, multilingual dictionary
|
||
subpaths, runtime dictionary swap, observable streaming variant, and a
|
||
hard 200-character DoS guard.
|
||
|
||
<!-- begin:auto-docs -->
|
||
## Documentation tree
|
||
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- wikipedia — <!-- begin:auto-docs --> _(no submodules…
|
||
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
|
||
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
|
||
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
|
||
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- wikipedia — <!-- begin:auto-docs --> _(no submodules…
|
||
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- azerty — <!-- begin:auto-docs --> _(no submodules)_…
|
||
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- azerty — <!-- begin:auto-docs --> _(no submodules)_…
|
||
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- date — <!-- begin:auto-docs --> _(no submodules)_ <!…
|
||
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - l33t-table — Provides the default character → lette…
|
||
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - l33t-table — Provides the default character → lette…
|
||
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->- date — <!-- begin:auto-docs --> _(no submodules)_ <!…
|
||
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||
- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
|
||
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
|
||
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
|
||
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
|
||
<!-- end:auto-docs --> - [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
|
||
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
|
||
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
|
||
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
|
||
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
|
||
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
|
||
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
|
||
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-…
|
||
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
|
||
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
|
||
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
|
||
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-…
|
||
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-doc…
|
||
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-doc…
|
||
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs…
|
||
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs…
|
||
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
|
||
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
|
||
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
|
||
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
|
||
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-docs --> _(no submodule…
|
||
- [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
|
||
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
|
||
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
|
||
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_- [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- wikipedia — <!-- begin:auto-docs --> _(no submodule…
|
||
- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-docs --> _(no submodules)_…
|
||
- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_- [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- azerty — <!-- begin:auto-docs --> _(no submodules)_…
|
||
- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs --> _(no submodules)_ <…
|
||
- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_- l33t-table — Provides the default character → lette…
|
||
- [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_- [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- date — <!-- begin:auto-docs --> _(no submodules)_ <…
|
||
- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
|
||
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
|
||
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
|
||
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
|
||
- [assess-reactive](./src/assess/assess-reactive.md) — Debounce + cancel-on-newer-input wrapper around `assess` for UI strength meters that update as the user types. Each new…
|
||
- [assess](./src/assess/assess.md) — <!-- begin:auto-docs --> _(no submodules)_- [dicts](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_ - [de](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/de/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [english-wikipedia](./src/dicts/en/english-wikipedia.md) — Frequency-ranked dictionary of the most common English tokens observed in Wikipedia. The matcher uses this to flag pass…
|
||
- [names](./src/dicts/en/names.md) — Frequency-ranked dictionaries of common US given names (male and female) and surnames. Names are over-represented in pa…
|
||
- [passwords](./src/dicts/en/passwords.md) — Frequency-ranked dictionary of the most common passwords observed across public breach corpora (RockYou, HaveIBeenPwned…
|
||
- [es](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/es/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [fr](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/fr/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [ru](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/ru/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [zh-Hans](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [wikipedia](./src/dicts/zh-Hans/wikipedia.md) — <!-- begin:auto-docs --> _(no submodules)_ - [load-dictionaries](./src/dicts/load-dictionaries.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_ - [error-codes](./src/errors/error-codes.md) — <!-- begin:auto-docs --> _(no submodules)_- [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_ - [feedback](./src/feedback/feedback.md) — <!-- begin:auto-docs --> _(no submodules)_- [graphs](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_ - [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [azerty](./src/graphs/azerty/azerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dvorak](./src/graphs/dvorak/dvorak.md) — <!-- begin:auto-docs --> _(no submodules)_ - [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [qwerty](./src/graphs/qwerty/qwerty.md) — <!-- begin:auto-docs --> _(no submodules)_ - [validate-graph](./src/graphs/validate-graph.md) — <!-- begin:auto-docs --> _(no submodules)_- [matchers](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_ - [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ - [date](./src/matchers/date/date.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ - [dictionary](./src/matchers/dictionary/dictionary.md) — <!-- begin:auto-docs --> _(no submodules)_ - [l33t-table](./src/matchers/dictionary/l33t-table.md) — Provides the default character → letter substitution table used by the `dictionaryMatch` matcher to recognise l33t-enco…
|
||
- [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ - [keyboard](./src/matchers/keyboard/keyboard.md) — <!-- begin:auto-docs --> _(no submodules)_ - [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ - [regex](./src/matchers/regex/regex.md) — <!-- begin:auto-docs --> _(no submodules)_ - [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ - [repeat](./src/matchers/repeat/repeat.md) — <!-- begin:auto-docs --> _(no submodules)_ - [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ - [sequence](./src/matchers/sequence/sequence.md) — <!-- begin:auto-docs --> _(no submodules)_ - [types](./src/matchers/types.md) — <!-- begin:auto-docs --> _(no submodules)_- [observability](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_ - [metrics](./src/observability/metrics.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ - [schemas](./src/schemas/schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [crack-times](./src/scoring/crack-times.md) — Maps a `guesses` count to seconds-to-crack under the four canonical attack scenarios from Wheeler 2016 section 5: onlin…
|
||
- [estimate-guesses](./src/scoring/estimate-guesses.md) — Implements the Wheeler 2016 section 4 closed-form guess estimates per pattern type: dictionary (rank × uppercase × l33t…
|
||
- [most-guessable-match-sequence](./src/scoring/most-guessable-match-sequence.md) — Picks the lowest-`Π guesses × k!` cover of the password from the union of pattern matches plus implicit bruteforce-char…
|
||
- [score](./src/scoring/score.md) — Maps a `guesses` count to a coarse integer score per Wheeler 2016 section 5. This score (`0`–`4`) is what most consumer…
|
||
|
||
## Install
|
||
|
||
```bash
|
||
bun add @suaveplan/password-strength
|
||
```
|
||
|
||
## Quick Start
|
||
|
||
```ts
|
||
import { assess } from "@suaveplan/password-strength";
|
||
|
||
const result = assess("Password1!");
|
||
console.log(result.score); // 0..4 bucket
|
||
console.log(result.guesses); // closed-form guess count
|
||
console.log(result.feedback.warning); // English-default UI string
|
||
console.log(result.crackTimes.offline_fast_hashing_1e10_per_second);
|
||
```
|
||
|
||
## Modules
|
||
|
||
| Module | Doc |
|
||
|---|---|
|
||
| `errors/error-codes` | [`src/errors/error-codes.md`](src/errors/error-codes.md) |
|
||
| `matchers/dictionary` | [`src/matchers/dictionary/dictionary.md`](src/matchers/dictionary/dictionary.md) |
|
||
| `matchers/dictionary/l33t-table` | [`src/matchers/dictionary/l33t-table.md`](src/matchers/dictionary/l33t-table.md) |
|
||
| `matchers/sequence` | [`src/matchers/sequence/sequence.md`](src/matchers/sequence/sequence.md) |
|
||
| `matchers/repeat` | [`src/matchers/repeat/repeat.md`](src/matchers/repeat/repeat.md) |
|
||
| `matchers/date` | [`src/matchers/date/date.md`](src/matchers/date/date.md) |
|
||
| `matchers/keyboard` | [`src/matchers/keyboard/keyboard.md`](src/matchers/keyboard/keyboard.md) |
|
||
| `matchers/regex` | [`src/matchers/regex/regex.md`](src/matchers/regex/regex.md) |
|
||
| `graphs/qwerty` | [`src/graphs/qwerty/qwerty.md`](src/graphs/qwerty/qwerty.md) |
|
||
| `graphs/dvorak` | [`src/graphs/dvorak/dvorak.md`](src/graphs/dvorak/dvorak.md) |
|
||
| `graphs/azerty` | [`src/graphs/azerty/azerty.md`](src/graphs/azerty/azerty.md) |
|
||
| `graphs/validate-graph` | [`src/graphs/validate-graph.md`](src/graphs/validate-graph.md) |
|
||
| `dicts/en/passwords` | [`src/dicts/en/passwords.md`](src/dicts/en/passwords.md) |
|
||
| `dicts/en/english-wikipedia` | [`src/dicts/en/english-wikipedia.md`](src/dicts/en/english-wikipedia.md) |
|
||
| `dicts/en/names` | [`src/dicts/en/names.md`](src/dicts/en/names.md) |
|
||
| `dicts/de/wikipedia` | [`src/dicts/de/wikipedia.md`](src/dicts/de/wikipedia.md) |
|
||
| `dicts/fr/wikipedia` | [`src/dicts/fr/wikipedia.md`](src/dicts/fr/wikipedia.md) |
|
||
| `dicts/es/wikipedia` | [`src/dicts/es/wikipedia.md`](src/dicts/es/wikipedia.md) |
|
||
| `dicts/zh-Hans/wikipedia` | [`src/dicts/zh-Hans/wikipedia.md`](src/dicts/zh-Hans/wikipedia.md) |
|
||
| `dicts/ru/wikipedia` | [`src/dicts/ru/wikipedia.md`](src/dicts/ru/wikipedia.md) |
|
||
| `dicts/load-dictionaries` | [`src/dicts/load-dictionaries.md`](src/dicts/load-dictionaries.md) |
|
||
| `scoring/score` | [`src/scoring/score.md`](src/scoring/score.md) |
|
||
| `scoring/crack-times` | [`src/scoring/crack-times.md`](src/scoring/crack-times.md) |
|
||
| `scoring/estimate-guesses` | [`src/scoring/estimate-guesses.md`](src/scoring/estimate-guesses.md) |
|
||
| `scoring/most-guessable-match-sequence` | [`src/scoring/most-guessable-match-sequence.md`](src/scoring/most-guessable-match-sequence.md) |
|
||
| `assess/assess` | [`src/assess/assess.md`](src/assess/assess.md) |
|
||
| `assess/assess-reactive` | [`src/assess/assess-reactive.md`](src/assess/assess-reactive.md) |
|
||
| `feedback/feedback` | [`src/feedback/feedback.md`](src/feedback/feedback.md) |
|
||
| `schemas` | [`src/schemas/schemas.md`](src/schemas/schemas.md) |
|
||
| `observability/metrics` | [`src/observability/metrics.md`](src/observability/metrics.md) |
|
||
|
||
## Features
|
||
|
||
- Six pattern matchers: dictionary (with l33t + reverse), sequence,
|
||
repeat, date, keyboard adjacency, regex
|
||
- DP cover with factorial penalty per Wheeler section 4
|
||
- Four crack-time scenarios, site-tunable via `adjustments`
|
||
- 5-bucket score (`0`–`4`) per Wheeler section 5
|
||
- 200-character DoS guard
|
||
- Streaming variant (`assessReactive`) with debounce + cancel-on-newer
|
||
- Runtime dictionary swap via `loadDictionaries`
|
||
- Multilingual dictionary subpaths (`en`, `de`, `fr`, `es`, `zh-Hans`, `ru`)
|
||
- Keyboard graph subpaths (`qwerty`, `dvorak`, `azerty`)
|
||
- Zod-validated boundaries at every public entry point
|
||
- OTel histogram + counters for assess duration, score distribution,
|
||
error code, and matcher hit count
|
||
|
||
## Baseline benchmarks
|
||
|
||
Run `bun run src/__benchmarks__/assess.bench.ts` to print baseline numbers
|
||
locally. Indicative timings on commodity hardware (single fork, no warmup):
|
||
|
||
| Bench | Mean |
|
||
|---|---|
|
||
| 8-char password | ~0.5 ms |
|
||
| 64-char password | ~5 ms |
|
||
| Dictionary-heavy | ~1 ms |
|
||
| DP n=100 | ~3 ms |
|
||
| DP n=199 | ~12 ms |
|
||
|
||
The 200-character DoS guard keeps p99 well under the 5 ms `it()` default.
|
||
|