password-intelligence
v0.4.1
Published
Framework-agnostic, Turkish-first password strength estimator. Regional pattern intelligence (names, surnames, football clubs, city plates, brands) on top of zxcvbn-ts, in a ~34 kB gzip default bundle.
Maintainers
Readme
Password Intelligence
Turkish-first, culturally-aware password strength estimation. No framework required. Wraps the zxcvbn-ts engine with a Turkish-specific threat layer, in ~37 kB gzip.
▶ Try it live
English · Türkçe
Runs in Node, Next.js, plain React, Deno, browsers, and React Native. Zero react or react-native dependency.
Building a React Native app? Install
react-native-password-intelligenceinstead — it wraps this package and adds an animated meter and a headless hook.
The problem
Standard password meters treat password123 as weak but miss regional patterns like
mehmet1907, karakartal, or askim34. These are among the most common passwords in Turkish
breach corpora, and a generic English wordlist scores them as strong.
Install
npm install password-intelligenceUse
import { analyzePassword } from 'password-intelligence';
analyzePassword('galatasaray1905').score; // 0 | 1 | 2 | 3 | 4
analyzePassword('galatasaray').feedback.warning;
// "Futbol takımı adları ve taraftar terimleri kolay tahmin edilir."
// Penalize values specific to this user
analyzePassword('mehmetyilmaz1907', ['Mehmet', 'Yılmaz', '[email protected]']);Turkish intelligence layer
12 categories, ~1,260 generated entries from 877 curated source terms (each expanded into normalized, compacted, and ASCII-folded variants): common names, surnames (382 from TÜİK/NVI), football clubs and fan slang, city names and plate codes, cultural/historic terms, romantic terms, religious/ideological terms, zodiac signs, brands, keyboard walks, and common passwords.
Plus a frequency-ordered top-4,000 English password list and all six keyboard adjacency graphs.
Configuration
import { configure, addCustomDictionary } from 'password-intelligence';
// Company-wide forbidden words (deduped, capped at 10,000)
addCustomDictionary(['Acme', 'AcmeCorp', 'AcmePay']);
// Restore the full 49,233-entry English list (adds ~229 kB gzip)
const { dictionary, adjacencyGraphs } = await import('@zxcvbn-ts/language-common');
configure({ dictionaries: dictionary, graphs: adjacencyGraphs });configure() is valid at any time, including after the first analysis — options are re-applied
lazily on the next call, so there is no initialization ordering to get wrong and
analyzePassword stays synchronous.
| Option | Purpose |
|---|---|
| dictionaries | Extra zxcvbn dictionaries, merged over the bundled ones key by key |
| graphs | Extra keyboard adjacency graphs, merged over the bundled ones layout by layout |
| translations | Replaces the bundled Turkish feedback strings; add a dictionaryWarnings map to translate the Turkish-category warnings too |
| disableTurkishDictionaries | Ship only the English list |
| disableBundledPasswords | Ship only the Turkish categories |
| maxLength | Characters analysed before truncation (default 256, matching @zxcvbn-ts/core) |
| useLevenshteinDistance, levenshteinThreshold | Passed through to zxcvbn |
configure() validates synchronously and throws a TypeError / RangeError on an invalid option
without touching the current configuration.
resetConfiguration() reverts everything set via configure(). It deliberately does not
clear the custom dictionary — that is clearCustomDictionary()'s job.
Custom dictionary words and per-call userInputs are matched in their Turkish, compact and
ASCII-folded forms, exactly like the bundled categories, so addCustomDictionary(['İkbalcan'])
catches ikbalcan, IKBALCAN and İkbalcan alike.
API
analyzePassword(password: string, userInputs?: readonly (string | number)[]): ZxcvbnResult
addCustomDictionary(words: readonly string[]): void
clearCustomDictionary(): void
configure(config: PasswordIntelligenceConfig): void
resetConfiguration(): void
subscribeToConfiguration(listener: () => void): () => void
getConfigurationVersion(): numbersubscribeToConfiguration / getConfigurationVersion notify consumers that cache results (the
React Native hook uses them) whenever configure, resetConfiguration, addCustomDictionary or
clearCustomDictionary changes the engine state.
Non-string passwords are coerced to '', input is normalised to NFC, and anything beyond
maxLength (default 256) is truncated before zxcvbn sees it. The cap bounds the quadratic
matcher's worst case; it does not make long inputs cheap.
Standards
NIST SP 800-63B-4 §3.1.1.2 Password Verifiers (HTML · DOI) requires that "verifiers SHALL compare the prospective secret against a blocklist that contains known commonly used, expected, or compromised passwords." Dictionary words and context-specific words, such as the name of the service, the username, and derivatives thereof appear there as example entries — the wording is "For example, the list may include…", not a mandated set. Verifiers must also "offer guidance to the subscriber to help the subscriber choose a strong password."
One sentence in that section matters more than the rest for a library like this one:
"The entire password SHALL be subject to comparison, not substrings or words that might be contained therein."
zxcvbn is a substring and pattern matcher by construction, which is the opposite of the
whole-password membership test §3.1.1.2 prescribes. So this library does not implement that
blocklist check, and no client-side scorer can. What it does give you is the guidance requirement
— Turkish feedback.warning and feedback.suggestions — plus corpora you can feed to a real
verifier-side blocklist, and userInputs / addCustomDictionary for context-specific words as
scoring signals.
It does not make you compliant. Enforcement belongs to the verifier and must happen server-side. Note also that §3.1.1.2 item 5 states "Verifiers and CSPs SHALL NOT impose other composition rules (e.g., requiring mixtures of different character types) for passwords" (§3.1.1.1 puts it as "Other composition requirements for passwords SHALL NOT be imposed.") — do not layer character-class rules on top of this score.
What this is not
- Not a password manager — does not store, transmit, or sync passwords.
- Not a hash function — pair with Argon2id (described in RFC 9106, an Informational IRTF/CFRG document rather than a standards-track spec) or scrypt, per the OWASP Password Storage Cheat Sheet; PBKDF2 when FIPS-140 validation is required, and bcrypt only for legacy systems.
- Not a generator — use a CSPRNG-backed generator.
- Not a server-side validator — the score is a UX hint, not an authorization gate.
Data provenance
The bundled password list and keyboard graphs are generated from
@zxcvbn-ts/language-common (MIT), itself derived from
dropbox/zxcvbn (MIT). See
THIRD_PARTY_NOTICES.md.
License
MIT © mobilteknolojileri
