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.

73 lines
2.1 KiB

  1. import base64
  2. import uuid
  3. from functools import wraps
  4. from typing import Optional, Callable
  5. from flask import request, Response, session
  6. from werkzeug.datastructures import Authorization
  7. from werkzeug.http import bytes_to_wsgi, wsgi_to_bytes
  8. def authenticate_with_password(username: str, password: str) -> bool:
  9. session['user'] = None
  10. return True
  11. def authenticate_with_token(username: str, token: str) -> bool:
  12. session['user'] = None
  13. return True
  14. def authentication_failed(auth_type: str) -> Response:
  15. return Response(
  16. status=401,
  17. headers={
  18. 'WWW-Authenticate': '%s realm="Login Required"' % auth_type
  19. })
  20. def parse_token_authorization_header(header_value) -> Optional[Authorization]:
  21. if not header_value:
  22. return
  23. value = wsgi_to_bytes(header_value)
  24. try:
  25. auth_type, auth_info = value.split(None, 1)
  26. auth_type = auth_type.lower()
  27. except ValueError:
  28. return
  29. if auth_type == b'token':
  30. try:
  31. username, token = base64.b64decode(auth_info).split(b':', 1)
  32. except Exception:
  33. return
  34. return Authorization('token', {'username': bytes_to_wsgi(username),
  35. 'password': bytes_to_wsgi(token)})
  36. def require_basic_auth(func: Callable) -> Callable:
  37. @wraps(func)
  38. def decorate(*args, **kwargs):
  39. auth = request.authorization
  40. if auth and authenticate_with_password(auth.username, auth.password):
  41. return func(*args, **kwargs)
  42. else:
  43. return authentication_failed('Basic')
  44. return decorate
  45. def require_token_auth(func: Callable) -> Callable:
  46. @wraps(func)
  47. def decorate(*args, **kwargs):
  48. token = parse_token_authorization_header(
  49. request.headers.get('WWW-Authenticate', None))
  50. if token and authenticate_with_token(token.username, token.password):
  51. return func(*args, **kwargs)
  52. else:
  53. return authentication_failed('Token')
  54. return decorate
  55. def generate_token() -> uuid.UUID:
  56. return uuid.uuid4()