A modern password validation library powered by zxcvbn with policy enforcement and CLI support.
Project description
FortifyPass - Real-World Password Security for Developers
Every day, companies get breached because someone picked
123456orpassword. Users think complexity is optional. Developers hope nobody notices. Security teams cry. FortifyPass guarantees your users pick passwords that actually protect them - real-world strong, actinable, and verifiable
Why Everyone will Agree
- Weak passwords are everywhere - your users do it, your friends do it, your systems get hacked.
- Length or character checks don't cut it - hackers exploit patterns, common words, and sequences.
- Feedback is terrible in almost every validator - users ignore it, reuse passwords, and risk breaches skyrocket.
Your system is only as secure as the weakest password. FortifyPass fixes that.
Why You'll Want This
FortifyPass doesn't just validate - it forces strong passwords and explains why:
- Real-world strength scoring powered by
zxcvbn - Policy enforcement: uppercase, lowercase, digits, special, characters, banned words
- Actionable feedback: your users actually learn to make secure passwords
- Plug-and-Play: works in Python, CLI, scripts, and future APIs
Quick Demo
fortifypass
FortifyPass version 0.2.1
Type .exit() to quit
Enter password: ··············
✗ Does not meet policy requirements
• Policy requirement: add at least one special character
✗ Too weak against common attacks
Score: 0/4
Strength: Very Weak
Feedback:
• Sequences like "abc" or "6543" are easy to guess.
• Avoid sequences.
------------------------------------------------------------
Enter password: ·················
✗ Too weak against common attacks
Score: 2/4
Strength: Moderate
Feedback:
• This is similar to a commonly used password.
• Add another word or two. Uncommon words are better.
• Capitalization doesn't help very much.
• Predictable substitutions like '@' instead of 'a' don't help very much.
------------------------------------------------------------
Enter password: ······························
✓ Strong against common attacks
Score: 4/4
Strength: Very Strong
------------------------------------------------------------
Enter password: ·······
Goodbye.
Non-Interactive / Pipe mode
echo "Str0ngP@ssw0rd!" | fortifypass
{
"valid": true,
"policy_passed": true,
"strength_passed": true,
"errors": [],
"score": 4,
"label": "Very Strong",
"feedback": []
}
Installation
Using pip (standard)
pip install fortifypass
Using uv (fast alternative)
Install uv (if not already) or see official installation guides
pip install uv
uv add fortifypass
if you're working in a project:
uv sync
From Source
git clone https://github.com/botshelo-mere/fortifypass.git
cd fortifypass
# Using pip
pip install .
# Using uv
uv sync
Dev / Testing
# Using pip
pip install "fortifypass[dev]"
# Using uv
uv sync --extra dev
Quick Start
Library Usage
from fortifypass import PasswordValidator
# Default policy: 12–64 chars, upper, lower, digit, special required
validator = PasswordValidator()
# --- validate() → (bool, list[str]) ---
valid, errors = validator.validate("Str0ngP@ssw0rd!")
print(valid) # True
print(errors) # []
valid, errors = validator.validate("weak")
print(valid) # False
print(errors) # ['Password must be at least 12 characters long', ...]
# --- estimate_strength() → dict ---
strength = validator.estimate_strength("Str0ngP@ssw0rd!")
print(strength["score"]) # 3
print(strength["label"]) # 'Strong'
print(strength["feedback"]) # []
# --- evaluate() — combines both in one call ---
result = validator.evaluate("Str0ngP@ssw0rd!")
# {
# "valid": True,
# "errors": [],
# "score": 3,
# "label": "Strong",
# "feedback": []
# }
Custom Policy
validator = PasswordValidator(
min_length=8,
max_length=32,
require_uppercase=True,
require_lowercase=True,
require_digit=True,
require_special=True,
special_chars="!@#$%",
allow_spaces=False,
banned_words=["password", "admin", "secret"]
)
valid, errors = validator.validate("Admin123!")
# valid=False → "Contains a banned word"
Configuration Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
min_length |
int |
12 |
Minimum password length |
max_length |
int |
64 |
Maximum password length |
require_uppercase |
bool |
True |
Require at least one uppercase letter |
require_lowercase |
bool |
True |
Require at least one lowercase letter |
require_digit |
bool |
True |
Require at least one digit |
require_special |
bool |
True |
Require at least one special character |
special_chars |
str |
"!@#$%^&*" |
Set of allowed special characters |
allow_spaces |
bool |
False |
Whether whitespace is permitted |
banned_words |
list[str] | None |
None |
Case-insensitive list of forbidden words |
min_score |
int |
0 |
Minimum zxcvbn score (0-4) |
ValueErroris raised on construction ifmin_length <= 0ormax_length < min_length.
ValueErroris raised on construction ifmin_score < 0or not0 <= min_score <= 4.
API Reference
PasswordValidator.validate(pwd: str) → Tuple[bool, List[str]]
Runs all configured policy rules against the password.
- Returns
(True, [])if all rules pass. - Returns
(False, [<error messages>])if any rule fails. - Raises
ValueErrorifpwdis not astr.
PasswordValidator.estimate_strength(pwd: str) → Dict[str, Any]
Uses zxcvbn to estimate password strength.
- Passwords longer than 72 characters are truncated before scoring (zxcvbn limit).
- Always returns a dictionary — never raises.
| Key | Type | Description |
|---|---|---|
score |
int |
0 (Very Weak) → 4 (Very Strong) |
label |
str |
Human-readable label |
feedback |
list[str] |
Warnings and suggestions from zxcvbn |
PasswordValidator.evaluate(pwd: str) → Dict[str, Any]
Combines validate() and estimate_strength() into a single result.
| Key | Type | Description |
|---|---|---|
valid |
bool |
Whether all policy rules passed |
policy_passed |
bool |
Policy Compliance |
strength_passed |
bool |
score >= min_core |
errors |
list[str] |
Policy error messages |
score |
int |
zxcvbn score 0–4 |
label |
str |
Strength label |
feedback |
list[str] |
zxcvbn feedback |
CLI Usage
Interactive Mode
fortifypass
# Or use uv
uv run fortifypass
- Password input is hidden (no echo).
- Type
.exit()to quit. - Press
Ctrl+Cto interrupt.
Non-Interactive / Pipe Mode
Pipe a password directly — output is JSON, exit code is 0 for score ≥ 3, 1 otherwise:
echo "Str0ngP@ssw0rd!" | fortifypass
Ideal for shell scripts and CI pipelines:
echo "$PASSWORD" | fortifypass && echo "Password accepted" || echo "Password rejected"
Exit code is 0 only if the password passes both policy and strength requirements
Strength Score Labels
| Score | Label | Meaning |
|---|---|---|
| 0 | Very Weak | Trivially crackable |
| 1 | Weak | Easy to crack |
| 2 | Moderate | Some resistance |
| 3 | Strong | Good security |
| 4 | Very Strong | Excellent security |
Scoring is provided by zxcvbn, which models real-world cracking strategies (dictionary attacks, keyboard patterns, etc.) rather than simple character-class rules.
Development
Running Tests
# All tests
uv run pytest
# With coverage report
uv run pytest --cov=fortifypass --cov-report=term-missing
# Verbose output
uv run pytest -v
# Run a specific test function
uv run pytest tests/test_validator.py::Testvalidate::test_validate_valid_password
Running Benchmarks
uv run pytest tests/test_performance_benchmarks.py --benchmark-only
Code Coverage
uv run pytest --cov=fortifypass --cov-branch --cov-report=html
# Open htmlcov/index.html in your browser
NOTE:
uv run pytestworks becausepytestis installed in the uv environment. Do not runpython test_validator.pydireclty - the test framework will not discover functions.
Version History
| Version | Changes |
|---|---|
| v0.2.1 | Fixed password score display issue, improved CLI output formatting, enhanced feedback, internal improvements for stability |
| v0.2.0 | Added zxcvbn strength estimation, evaluate() API, banned words, full type annotations, colorama CLI, pipe mode, comprehensive test suite |
| v0.1.1 | Infrastructure improvements, packaging fixes |
| v0.1.0 | Initial public release |
License
This project is licensed under the MIT License — see LICENSE.md for details.
Author
Botshelo Mere
GitHub: botshelo-mere
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fortifypass-0.2.1.tar.gz.
File metadata
- Download URL: fortifypass-0.2.1.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a2b34357d1232c40080e8079d14a65de878908d520d3d4891d1935806dd7bb6
|
|
| MD5 |
fcf66f55fb88961e35a0c8a9fd93bd10
|
|
| BLAKE2b-256 |
4fbaee7d0fd6121677aa0f4cee82a2a8405d55f71f1bdd48a0f940d923102d6f
|
File details
Details for the file fortifypass-0.2.1-py3-none-any.whl.
File metadata
- Download URL: fortifypass-0.2.1-py3-none-any.whl
- Upload date:
- Size: 9.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf334fd473a88f79d631c8ae093f877c83ee4cedd49b05617cf7846d0a518605
|
|
| MD5 |
7a2afe63dd692c7040254e12654eae9b
|
|
| BLAKE2b-256 |
da3ac05196cb7be8c9657222b95457a349e93b9f6ebc053d2fea66cd096cf9ed
|