@misok/password-checker
v0.1.4
Published
Multilingual password analysis with Bloom filtering and optional HIBP checks
Maintainers
Readme
password-checker
Lightweight, multilingual password-strength analysis core for browser-first password analysis.
⚠️ Current maturity: pre-release. API can still change.
Quick start (copy-paste)
npm install @misok/password-checkerimport { PasswordDefenseCore } from '@misok/password-checker';
import bloom from '@misok/password-checker/fixtures/blooms.generated.json' assert { type: 'json' };
const checker = new PasswordDefenseCore({
defaultLanguage: bloom.defaultLanguage,
locale: 'en',
languages: bloom.languages,
activeLanguages: ['fi', 'en']
});
const result = checker.analyze('correct-horse-battery-staple', { locale: 'en' });
console.log(result.score, result.label, result.riskFlags);Tip: Use this as a UX guidance layer in frontend flows, not as a standalone auth control.
Simpler option: ship your own Bloom JSON
If JSON import assertions feel too complex for your runtime, generate and bundle your own Bloom file in your app repository.
- Create a build config (example):
{
"defaultLanguage": "en",
"defaults": { "size": 500000, "hashes": 12, "minTokenLength": 4 },
"languages": {
"en": { "input": "./wordlists/en.txt" },
"fi": { "input": "./wordlists/fi.txt", "minTokenLength": 3 }
},
"output": "./src/security/blooms.generated.json"
}- Generate Bloom payloads during your build:
# Use your local bloom builder script (for example, copied/adapted from this repo)
node ./scripts/build-bloom.js ./bloom.config.json- Import your local generated file (clearer import path):
import { PasswordDefenseCore } from '@misok/password-checker';
import bloom from './security/blooms.generated.json' assert { type: 'json' };What this library does
password-checker evaluates password guessability with a practical, browser-friendly model:
- Entropy estimate (length + character set diversity)
- Structural penalties (common sequences, repetition)
- Dictionary pattern detection via configurable Bloom filters
It is designed for fast client-side checks and supports multiple languages (e.g. Finnish + English).
Features
- ✅ Multilingual Bloom filter support (
fi,en, custom) - ✅ Config-driven Bloom regeneration from text wordlists
- ✅ Works in browser debug flow and Node.js tests
- ✅ Adjustable Bloom parameters per language (
size,hashes,minTokenLength) - ✅ Passphrase-aware scoring for long multi-word passwords
Project structure
password-checker/
├─ config/
│ └─ bloom.config.json # bloom build config
├─ wordlists/
│ ├─ en.txt # english source words
│ └─ fi.txt # finnish source words
├─ scripts/
│ └─ build-bloom.js # regenerate bloom payloads from wordlists
├─ fixtures/
│ └─ blooms.generated.json # generated bloom data (input for runtime)
├─ src/
│ └─ index.js # PasswordDefenseCore implementation
├─ debug/
│ └─ index.html # local debug UI
└─ test/
└─ smoke.js # smoke testInstallation (local repo usage)
cd projects/password-checker
npm install(There are no external runtime dependencies currently.)
Quick start
cd projects/password-checker
npm run build:bloom
npm testExpected smoke output includes checks like:
lintu truepassword truerandom false
Local debug page
cd projects/password-checker
npm run build:bloom
npm run debug
# open http://localhost:4173/debug/The debug page lets you:
- toggle active languages (
fi,en) - test analyzer output in real time
- run quick bloom hit checks for sample words
- toggle optional HIBP checks and inspect returned status/count/error
Hosted debug page (GitHub Pages):
- https://misolith.github.io/password-checker/debug/
How to use
1) In a browser HTML page
<script type="module">
import { PasswordDefenseCore } from './src/index.js';
import bloom from './fixtures/blooms.generated.json' assert { type: 'json' };
const checker = new PasswordDefenseCore({
defaultLanguage: bloom.defaultLanguage,
locale: 'en',
languages: bloom.languages,
activeLanguages: ['fi', 'en']
});
const result = checker.analyze('passwordaurinko');
console.log(result);
</script>2) In a Node.js project
import { PasswordDefenseCore } from './src/index.js';
import fs from 'fs';
const bloom = JSON.parse(fs.readFileSync('./fixtures/blooms.generated.json', 'utf8'));
const checker = new PasswordDefenseCore({
defaultLanguage: bloom.defaultLanguage,
locale: 'fi',
languages: bloom.languages,
activeLanguages: ['fi', 'en']
});
console.log(checker.checkBloom('password'));
console.log(checker.analyze('passwordaurinko', { locale: 'fi' }));analyze() now also exposes:
strategy:random,word_based,mixed, orpassphrasedictionaryWordCount: distinct dictionary words detected in the passwordscoreBreakdown.bonuses.passphrase: uplift applied to strong multi-word passphrases
3) Optional scoring config overrides
You can tune scoring factors (for example from your factor-tuning workflow) via scoring config:
const checker = new PasswordDefenseCore({
defaultLanguage: bloom.defaultLanguage,
locale: 'en',
languages: bloom.languages,
activeLanguages: ['fi', 'en'],
scoring: {
baselineMultiplier: 0.8,
penalties: {
sequence: 24,
year: 32
}
}
});4) Language switching at runtime
checker.setLocale('fi');
checker.setActiveLanguages(['fi']);5) Optional HaveIBeenPwned (HIBP) check
const checker = new PasswordDefenseCore({
defaultLanguage: bloom.defaultLanguage,
locale: 'en',
languages: bloom.languages,
activeLanguages: ['fi', 'en'],
hibp: { enabled: true }
});
const result = await checker.analyzeAsync('password123');
console.log(result.hibp); // { enabled: true, pwned: true/false, count }HIBP uses k-anonymity: only the SHA-1 hash prefix is sent to the API.
Bloom configuration
Edit config/bloom.config.json:
{
"defaultLanguage": "en",
"defaults": {
"size": 120000,
"hashes": 7,
"minTokenLength": 3
},
"languages": {
"en": { "input": "wordlists/en.txt" },
"fi": { "input": "wordlists/fi.txt" }
},
"output": "fixtures/blooms.generated.json"
}Parameter notes
size(bits): larger => fewer false positives, larger payloadhashes: more hashes can reduce false positives up to a pointminTokenLength: ignore too-short words (helps reduce noisy matches)
Included open-source wordlist example
The repository now includes:
wordlists/en-frequency-20k.txt
This is a generated open-source example list (top 20k normalized English tokens) from:
hermitdave/FrequencyWords(content/2018/en/en_50k.txt)
Use it directly in config/bloom.config.json if you want a stronger default English Bloom profile.
Add a new language
- Create a new wordlist file:
wordlists/<lang>.txt- one token per line
- lowercase recommended
- Add language entry in
config/bloom.config.json - Regenerate bloom payloads:
npm run build:bloom- Enable language at runtime:
core.setActiveLanguages(['fi', 'en', '<lang>']);NPM scripts
npm run build:bloom→ generatefixtures/blooms.generated.jsonnpm test→ run smoke testnpm run debug→ serve repo locally for debug page
Security model & limitations
This library is a UX advisory password checker, not a standalone security control.
Use it with server-side controls such as:
- breach/password policy enforcement
- rate limiting
- MFA / passkeys
- secure credential storage (e.g. Argon2id/bcrypt in backend)
Known limitations:
- Not yet optimized for full morphological analysis (important for Finnish compounds/inflections)
- Scoring logic is practical, not a formal cryptographic crack-time simulator
- Bloom filters may introduce probabilistic noise depending on configuration
- API may still evolve before 1.0
Passphrase behavior
Long multi-word passphrases are no longer treated the same way as short dictionary compounds.
passwordaurinkostays word-based and heavily penalizedcorrect-horse-battery-staplecan score as a strong passphrase- year/sequence patterns still suppress passphrase uplift
Development policy
Stability-first development policy:
Changes should remain backward-compatible whenever possible and include runnable test/debug verification.
License
MIT (planned for public release).
