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.

88 lines
1.9 KiB

  1. """
  2. Service to handle authentication
  3. """
  4. import uuid
  5. from datetime import datetime
  6. from typing import Optional, Tuple
  7. from nacl import pwhash
  8. from nacl.exceptions import InvalidkeyError
  9. from atheneum.model import User, UserToken
  10. from atheneum.service import user_service, user_token_service
  11. def generate_token() -> uuid.UUID:
  12. """
  13. Generate a unique token
  14. :return:
  15. """
  16. return uuid.uuid4()
  17. def get_password_hash(password: str) -> Tuple[str, int]:
  18. """
  19. Retrieve argon2id password hash.
  20. :param password: plaintext password to convert
  21. :return: Tuple[password_hash, password_revision]
  22. """
  23. return pwhash.argon2id.str(password.encode('utf8')).decode('utf8'), 1
  24. def is_valid_password(user: User, password: str) -> bool:
  25. """
  26. User password must pass pwhash verify
  27. :param user:
  28. :param password:
  29. :return:
  30. """
  31. assert user
  32. try:
  33. return pwhash.verify(
  34. user.password_hash.encode('utf8'), password.encode('utf8'))
  35. except InvalidkeyError:
  36. pass
  37. return False
  38. def is_valid_token(user_token: Optional[UserToken]) -> bool:
  39. """
  40. Token must be enabled and if it has an expiration, it must be
  41. greater than now.
  42. :param user_token:
  43. :return:
  44. """
  45. if user_token is None:
  46. return False
  47. if not user_token.enabled:
  48. return False
  49. if (user_token.expiration_time is not None
  50. and user_token.expiration_time < datetime.utcnow()):
  51. return False
  52. return True
  53. def bump_login(user: Optional[User]) -> None:
  54. """
  55. Update the last login time for the user
  56. :param user:
  57. :return:
  58. """
  59. if user is not None:
  60. user_service.update_last_login_time(user)
  61. def logout(user_token: Optional[UserToken] = None) -> None:
  62. """
  63. Remove a user_token associated with a client session
  64. :param user_token:
  65. :return:
  66. """
  67. if user_token is not None:
  68. user_token_service.delete(user_token)