This commit is contained in:
2025-10-23 18:10:34 +02:00
parent 5c2691b070
commit 9a64ca5b01
14 changed files with 598 additions and 149 deletions

View File

@@ -48,6 +48,10 @@ class AuthService:
self._hash: Optional[str] = settings.master_password_hash
# In-memory failed attempts per identifier. Values are dicts with
# keys: count, last, locked_until
# WARNING: In-memory storage resets on process restart.
# This is acceptable for development but PRODUCTION deployments
# should use Redis or a database to persist failed login attempts
# and prevent bypass via process restart.
self._failed: Dict[str, Dict] = {}
# Policy
self.max_attempts = 5
@@ -71,18 +75,42 @@ class AuthService:
def setup_master_password(self, password: str) -> None:
"""Set the master password (hash and store in memory/settings).
Enforces strong password requirements:
- Minimum 8 characters
- Mixed case (upper and lower)
- At least one number
- At least one special character
For now we update only the in-memory value and
settings.master_password_hash. A future task should persist this
to a config file.
Args:
password: The password to set
Raises:
ValueError: If password doesn't meet requirements
"""
# Length check
if len(password) < 8:
raise ValueError("Password must be at least 8 characters long")
# Basic strength checks
# Mixed case check
if password.islower() or password.isupper():
raise ValueError("Password must include mixed case")
raise ValueError(
"Password must include both uppercase and lowercase letters"
)
# Number check
if not any(c.isdigit() for c in password):
raise ValueError("Password must include at least one number")
# Special character check
if password.isalnum():
# encourage a special character
raise ValueError("Password should include a symbol or punctuation")
raise ValueError(
"Password must include at least one special character "
"(symbol or punctuation)"
)
h = self._hash_password(password)
self._hash = h