Coverage for src / mysingle / auth / security / password.py: 85%

20 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-01 23:57 +0900

1import secrets 

2import string 

3 

4from pwdlib import PasswordHash 

5from pwdlib.hashers.argon2 import Argon2Hasher 

6from pwdlib.hashers.bcrypt import BcryptHasher 

7 

8 

9class PasswordHelper: 

10 def __init__(self, password_hash: PasswordHash | None = None) -> None: 

11 if password_hash is None: 

12 self.password_hash = PasswordHash( 

13 ( 

14 Argon2Hasher(), 

15 BcryptHasher(), 

16 ) 

17 ) 

18 else: 

19 self.password_hash = password_hash # pragma: no cover 

20 

21 def verify_and_update( 

22 self, plain_password: str, hashed_password: str 

23 ) -> tuple[bool, str | None]: 

24 return self.password_hash.verify_and_update(plain_password, hashed_password) 

25 

26 def hash(self, password: str) -> str: 

27 return self.password_hash.hash(password) 

28 

29 def generate(self) -> str: 

30 return secrets.token_urlsafe() 

31 

32 def generate_secure_password(self, length: int = 12) -> str: 

33 characters = string.ascii_letters + string.digits + string.punctuation 

34 password = "".join(secrets.choice(characters) for _ in range(length)) 

35 return password 

36 

37 

38password_helper = PasswordHelper()