Testeur de Politique de Mots de Passe
Testez les mots de passe contre des règles de politique configurables.
Policy Rules
Questions Fréquentes
Implémentation du Code
import re
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class PasswordPolicy:
min_length: int = 8
max_length: int = 128
require_uppercase: bool = True
require_lowercase: bool = True
require_digit: bool = True
require_symbol: bool = True
min_unique_chars: int = 5
forbidden_patterns: list[str] = field(default_factory=lambda: [
r"(..)\1{2,}", # repeated two-char block 3+ times
r"(.)\1{3,}", # same char 4+ times in a row
r"(?i)password", # literal word "password"
r"(?i)qwerty",
])
symbol_chars: str = r"!@#$%^&*()-_=+[]{}|;':",./<>?"
@dataclass
class PolicyResult:
passed: bool
violations: list[str] = field(default_factory=list)
score: int = 0 # 0-100
def check_password(password: str, policy: Optional[PasswordPolicy] = None) -> PolicyResult:
if policy is None:
policy = PasswordPolicy()
violations: list[str] = []
score = 0
# Length checks
if len(password) < policy.min_length:
violations.append(f"Too short: minimum {policy.min_length} characters")
elif len(password) >= policy.min_length:
score += 25
if len(password) > policy.max_length:
violations.append(f"Too long: maximum {policy.max_length} characters")
# Character class checks
if policy.require_uppercase and not re.search(r"[A-Z]", password):
violations.append("Must contain at least one uppercase letter")
else:
score += 15
if policy.require_lowercase and not re.search(r"[a-z]", password):
violations.append("Must contain at least one lowercase letter")
else:
score += 15
if policy.require_digit and not re.search(r"\d", password):
violations.append("Must contain at least one digit")
else:
score += 15
if policy.require_symbol and not re.search(
f"[{re.escape(policy.symbol_chars)}]", password
):
violations.append("Must contain at least one symbol")
else:
score += 15
# Unique characters
if len(set(password)) < policy.min_unique_chars:
violations.append(f"Must use at least {policy.min_unique_chars} different characters")
else:
score += 15
# Forbidden patterns
for pattern in policy.forbidden_patterns:
if re.search(pattern, password):
violations.append(f"Contains forbidden pattern: {pattern}")
passed = len(violations) == 0
return PolicyResult(passed=passed, violations=violations, score=min(score, 100))
# Example usage
if __name__ == "__main__":
tests = ["abc", "Password1!", "C0rrectH0rseBatteryStaple!"]
policy = PasswordPolicy(min_length=12)
for pwd in tests:
result = check_password(pwd, policy)
print(f"{pwd!r}: passed={result.passed}, score={result.score}")
for v in result.violations:
print(f" - {v}")Comments & Feedback
Comments are powered by Giscus. Sign in with GitHub to leave a comment.