feat: 5.1-3 Создать модуль app/core/passwords.py
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
from argon2 import PasswordHasher
|
||||||
|
from argon2.exceptions import InvalidHashError, VerifyMismatchError
|
||||||
|
from argon2.low_level import Type
|
||||||
|
from zxcvbn import zxcvbn
|
||||||
|
|
||||||
|
from app.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
class WeakPasswordError(ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_hasher = PasswordHasher(
|
||||||
|
time_cost=3,
|
||||||
|
memory_cost=65536,
|
||||||
|
parallelism=4,
|
||||||
|
hash_len=32,
|
||||||
|
salt_len=16,
|
||||||
|
type=Type.ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _peppered(password: str) -> str:
|
||||||
|
return password + settings.password_pepper
|
||||||
|
|
||||||
|
|
||||||
|
# возвращает хэш Argon2id от password + pepper;
|
||||||
|
def hash_password(password: str) -> str:
|
||||||
|
return _hasher.hash(_peppered(password))
|
||||||
|
|
||||||
|
|
||||||
|
# проверяет соответствие
|
||||||
|
def verify_password(password: str, hashed: str) -> bool:
|
||||||
|
try:
|
||||||
|
return _hasher.verify(hashed, _peppered(password))
|
||||||
|
except (VerifyMismatchError, InvalidHashError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# проверяет политику
|
||||||
|
def validate_policy(password: str, user_inputs: list[str] | None = None) -> None:
|
||||||
|
# длина не меньше settings.password_min_length;
|
||||||
|
if len(password) < settings.password_min_length:
|
||||||
|
raise WeakPasswordError(
|
||||||
|
f"Password must be >= {settings.password_min_length} chars"
|
||||||
|
)
|
||||||
|
result = zxcvbn(password, user_inputs=user_inputs or [])
|
||||||
|
# оценка стойкости через zxcvbn должна быть не ниже 3 (по шкале 0–4);
|
||||||
|
if result["score"] < 3:
|
||||||
|
raise WeakPasswordError("Password is too weak")
|
||||||
Reference in New Issue
Block a user