An ebook/comic library service and web client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
2.2 KiB

  1. """Service to handle authentication."""
  2. import re
  3. from datetime import datetime
  4. from typing import Optional
  5. from nacl import pwhash
  6. from nacl.exceptions import InvalidkeyError
  7. from atheneum import errors
  8. from atheneum.model import User, UserToken
  9. from atheneum.service import user_token_service
  10. def validate_password_strength(proposed_password: str) -> str:
  11. """Validate that a password meets minimum strength requirements."""
  12. # calculating the length
  13. length_error = len(proposed_password) < 8
  14. # searching for digits
  15. digit_error = re.search(r"\d", proposed_password) is None
  16. # searching for uppercase
  17. uppercase_error = re.search(r"[A-Z]", proposed_password) is None
  18. # searching for lowercase
  19. lowercase_error = re.search(r"[a-z]", proposed_password) is None
  20. if length_error or digit_error or uppercase_error or lowercase_error:
  21. raise errors.ValidationError(
  22. ' '.join(['The password must be at least 8 characters long.',
  23. 'Contain one or more digits,',
  24. 'one or more uppercase characters,',
  25. 'and one or more lowercase characters']))
  26. return proposed_password
  27. def is_valid_password(user: User, password: str) -> bool:
  28. """
  29. User password must pass pwhash verify.
  30. :param user:
  31. :param password:
  32. :return:
  33. """
  34. assert user
  35. try:
  36. return pwhash.verify(
  37. user.password_hash.encode('utf8'), password.encode('utf8'))
  38. except InvalidkeyError:
  39. pass
  40. return False
  41. def is_valid_token(user_token: Optional[UserToken]) -> bool:
  42. """
  43. Validate a token.
  44. Token must be enabled and if it has an expiration, it must be greater
  45. than now.
  46. :param user_token:
  47. :return:
  48. """
  49. if user_token is None:
  50. return False
  51. if not user_token.enabled:
  52. return False
  53. if (user_token.expiration_time is not None
  54. and user_token.expiration_time < datetime.utcnow()):
  55. return False
  56. return True
  57. def logout(user_token: Optional[UserToken] = None) -> None:
  58. """
  59. Remove a user_token associated with a client session.
  60. :param user_token:
  61. :return:
  62. """
  63. if user_token is not None:
  64. user_token_service.delete(user_token)