tokens.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.core.auth.tokens
  4. ~~~~~~~~~~~~~~~~~~~~~~~~
  5. This module provides ways of interacting
  6. with tokens in FlaskBB
  7. :copyright: (c) 2014-2018 by the FlaskBB Team.
  8. :license: BSD, see LICENSE for more details
  9. """
  10. from abc import ABC, abstractmethod
  11. import attr
  12. from flask_babelplus import gettext as _
  13. from .exceptions import BaseFlaskBBError
  14. class TokenError(BaseFlaskBBError):
  15. """
  16. Raised when there is an issue with deserializing
  17. a token. Has helper classmethods to ensure
  18. consistent verbiage.
  19. :param str reason: An explanation of why the token is invalid
  20. """
  21. def __init__(self, reason):
  22. self.reason = reason
  23. super(TokenError, self).__init__(reason)
  24. @classmethod
  25. def invalid(cls):
  26. """
  27. Used to raise an exception about a token that is invalid
  28. due to being signed incorrectly, has been tampered with,
  29. is unparsable or contains an inappropriate action.
  30. """
  31. return cls(_('Token is invalid'))
  32. @classmethod
  33. def expired(cls):
  34. """
  35. Used to raise an exception about a token that has expired and is
  36. no longer usable.
  37. """
  38. return cls(_('Token is expired'))
  39. # in theory this would never be raised
  40. # but it's provided for a generic catchall
  41. # when processing goes horribly wrong
  42. @classmethod # pragma: no cover
  43. def bad(cls):
  44. return cls(_('Token cannot be processed'))
  45. # holder for token actions
  46. # not an enum so plugins can add to it
  47. class TokenActions:
  48. """
  49. Collection of token actions.
  50. .. note::
  51. This is just a class rather than an enum because enums cannot be
  52. extended at runtime which would limit the number of token actions
  53. to the ones implemented by FlaskBB itself and block extension of
  54. tokens by plugins.
  55. """
  56. RESET_PASSWORD = 'reset_password'
  57. ACTIVATE_ACCOUNT = 'activate_account'
  58. @attr.s(frozen=True, eq=True, order=True, hash=True)
  59. class Token(object):
  60. """
  61. :param int user_id:
  62. :param str operation: An operation taken from
  63. :class:`TokenActions<flaskbb.core.tokens.TokenActions>`
  64. """
  65. user_id = attr.ib()
  66. operation = attr.ib()
  67. class TokenSerializer(ABC):
  68. """
  69. """
  70. @abstractmethod
  71. def dumps(self, token):
  72. """
  73. This method is abstract.
  74. Used to transform a token into a string representation of it.
  75. :param token:
  76. :type token: :class:`Token<flaskbb.core.tokens.Token>`
  77. :returns str:
  78. """
  79. pass
  80. @abstractmethod
  81. def loads(self, raw_token):
  82. """
  83. This method is abstract
  84. Used to transform a string representation of a token into an
  85. actual :class:`Token<flaskbb.core.tokens.Token>` instance
  86. :param str raw_token:
  87. :returns token: The parsed token
  88. :rtype: :class:`Token<flaskbb.core.tokens.Token`>
  89. """
  90. pass
  91. class TokenVerifier(ABC):
  92. """
  93. Used to verify the validatity of tokens post
  94. deserialization, such as an email matching the
  95. user id in the provided token.
  96. Should raise a
  97. :class:`ValidationError<flaskbb.core.exceptions.ValidationError>`
  98. if verification fails.
  99. """
  100. @abstractmethod
  101. def verify_token(self, token, **kwargs):
  102. """
  103. This method is abstract.
  104. :param token: The parsed token to verify
  105. :param kwargs: Arbitrary context for validation of the token
  106. :type token: :class:`Token<flaskbb.core.tokens.Token>`
  107. """
  108. pass
  109. def __call__(self, token, **kwargs):
  110. return self.verify_token(token, **kwargs)