]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/itsdangerous/signer.py
5 from .encoding
import _base64_alphabet
6 from .encoding
import base64_decode
7 from .encoding
import base64_encode
8 from .encoding
import want_bytes
9 from .exc
import BadSignature
11 _t_str_bytes
= _t
.Union
[str, bytes]
12 _t_opt_str_bytes
= _t
.Optional
[_t_str_bytes
]
13 _t_secret_key
= _t
.Union
[_t
.Iterable
[_t_str_bytes
], _t_str_bytes
]
16 class SigningAlgorithm
:
17 """Subclasses must implement :meth:`get_signature` to provide
18 signature generation functionality.
21 def get_signature(self
, key
: bytes, value
: bytes) -> bytes:
22 """Returns the signature for the given key and value."""
23 raise NotImplementedError()
25 def verify_signature(self
, key
: bytes, value
: bytes, sig
: bytes) -> bool:
26 """Verifies the given signature matches the expected
29 return hmac
.compare_digest(sig
, self
.get_signature(key
, value
))
32 class NoneAlgorithm(SigningAlgorithm
):
33 """Provides an algorithm that does not perform any signing and
34 returns an empty signature.
37 def get_signature(self
, key
: bytes, value
: bytes) -> bytes:
41 class HMACAlgorithm(SigningAlgorithm
):
42 """Provides signature generation using HMACs."""
44 #: The digest method to use with the MAC algorithm. This defaults to
45 #: SHA1, but can be changed to any other function in the hashlib
47 default_digest_method
: _t
.Any
= staticmethod(hashlib
.sha1
)
49 def __init__(self
, digest_method
: _t
.Any
= None):
50 if digest_method
is None:
51 digest_method
= self
.default_digest_method
53 self
.digest_method
: _t
.Any
= digest_method
55 def get_signature(self
, key
: bytes, value
: bytes) -> bytes:
56 mac
= hmac
.new(key
, msg
=value
, digestmod
=self
.digest_method
)
60 def _make_keys_list(secret_key
: _t_secret_key
) -> _t
.List
[bytes]:
61 if isinstance(secret_key
, (str, bytes)):
62 return [want_bytes(secret_key
)]
64 return [want_bytes(s
) for s
in secret_key
]
68 """A signer securely signs bytes, then unsigns them to verify that
69 the value hasn't been changed.
71 The secret key should be a random string of ``bytes`` and should not
72 be saved to code or version control. Different salts should be used
73 to distinguish signing in different contexts. See :doc:`/concepts`
74 for information about the security of the secret key and salt.
76 :param secret_key: The secret key to sign and verify with. Can be a
77 list of keys, oldest to newest, to support key rotation.
78 :param salt: Extra key to combine with ``secret_key`` to distinguish
79 signatures in different contexts.
80 :param sep: Separator between the signature and value.
81 :param key_derivation: How to derive the signing key from the secret
82 key and salt. Possible values are ``concat``, ``django-concat``,
83 or ``hmac``. Defaults to :attr:`default_key_derivation`, which
84 defaults to ``django-concat``.
85 :param digest_method: Hash function to use when generating the HMAC
86 signature. Defaults to :attr:`default_digest_method`, which
87 defaults to :func:`hashlib.sha1`. Note that the security of the
88 hash alone doesn't apply when used intermediately in HMAC.
89 :param algorithm: A :class:`SigningAlgorithm` instance to use
90 instead of building a default :class:`HMACAlgorithm` with the
93 .. versionchanged:: 2.0
94 Added support for key rotation by passing a list to
97 .. versionchanged:: 0.18
98 ``algorithm`` was added as an argument to the class constructor.
100 .. versionchanged:: 0.14
101 ``key_derivation`` and ``digest_method`` were added as arguments
102 to the class constructor.
105 #: The default digest method to use for the signer. The default is
106 #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or
107 #: compatible object. Note that the security of the hash alone
108 #: doesn't apply when used intermediately in HMAC.
110 #: .. versionadded:: 0.14
111 default_digest_method
: _t
.Any
= staticmethod(hashlib
.sha1
)
113 #: The default scheme to use to derive the signing key from the
114 #: secret key and salt. The default is ``django-concat``. Possible
115 #: values are ``concat``, ``django-concat``, and ``hmac``.
117 #: .. versionadded:: 0.14
118 default_key_derivation
: str = "django-concat"
122 secret_key
: _t_secret_key
,
123 salt
: _t_opt_str_bytes
= b
"itsdangerous.Signer",
124 sep
: _t_str_bytes
= b
".",
125 key_derivation
: _t
.Optional
[str] = None,
126 digest_method
: _t
.Optional
[_t
.Any
] = None,
127 algorithm
: _t
.Optional
[SigningAlgorithm
] = None,
129 #: The list of secret keys to try for verifying signatures, from
130 #: oldest to newest. The newest (last) key is used for signing.
132 #: This allows a key rotation system to keep a list of allowed
133 #: keys and remove expired ones.
134 self
.secret_keys
: _t
.List
[bytes] = _make_keys_list(secret_key
)
135 self
.sep
: bytes = want_bytes(sep
)
137 if self
.sep
in _base64_alphabet
:
139 "The given separator cannot be used because it may be"
140 " contained in the signature itself. ASCII letters,"
141 " digits, and '-_=' must not be used."
145 salt
= want_bytes(salt
)
147 salt
= b
"itsdangerous.Signer"
151 if key_derivation
is None:
152 key_derivation
= self
.default_key_derivation
154 self
.key_derivation
: str = key_derivation
156 if digest_method
is None:
157 digest_method
= self
.default_digest_method
159 self
.digest_method
: _t
.Any
= digest_method
161 if algorithm
is None:
162 algorithm
= HMACAlgorithm(self
.digest_method
)
164 self
.algorithm
: SigningAlgorithm
= algorithm
167 def secret_key(self
) -> bytes:
168 """The newest (last) entry in the :attr:`secret_keys` list. This
169 is for compatibility from before key rotation support was added.
171 return self
.secret_keys
[-1]
173 def derive_key(self
, secret_key
: _t_opt_str_bytes
= None) -> bytes:
174 """This method is called to derive the key. The default key
175 derivation choices can be overridden here. Key derivation is not
176 intended to be used as a security method to make a complex key
177 out of a short password. Instead you should use large random
180 :param secret_key: A specific secret key to derive from.
181 Defaults to the last item in :attr:`secret_keys`.
183 .. versionchanged:: 2.0
184 Added the ``secret_key`` parameter.
186 if secret_key
is None:
187 secret_key
= self
.secret_keys
[-1]
189 secret_key
= want_bytes(secret_key
)
191 if self
.key_derivation
== "concat":
192 return _t
.cast(bytes, self
.digest_method(self
.salt
+ secret_key
).digest())
193 elif self
.key_derivation
== "django-concat":
195 bytes, self
.digest_method(self
.salt
+ b
"signer" + secret_key
).digest()
197 elif self
.key_derivation
== "hmac":
198 mac
= hmac
.new(secret_key
, digestmod
=self
.digest_method
)
199 mac
.update(self
.salt
)
201 elif self
.key_derivation
== "none":
204 raise TypeError("Unknown key derivation method")
206 def get_signature(self
, value
: _t_str_bytes
) -> bytes:
207 """Returns the signature for the given value."""
208 value
= want_bytes(value
)
209 key
= self
.derive_key()
210 sig
= self
.algorithm
.get_signature(key
, value
)
211 return base64_encode(sig
)
213 def sign(self
, value
: _t_str_bytes
) -> bytes:
214 """Signs the given string."""
215 value
= want_bytes(value
)
216 return value
+ self
.sep
+ self
.get_signature(value
)
218 def verify_signature(self
, value
: _t_str_bytes
, sig
: _t_str_bytes
) -> bool:
219 """Verifies the signature for the given value."""
221 sig
= base64_decode(sig
)
225 value
= want_bytes(value
)
227 for secret_key
in reversed(self
.secret_keys
):
228 key
= self
.derive_key(secret_key
)
230 if self
.algorithm
.verify_signature(key
, value
, sig
):
235 def unsign(self
, signed_value
: _t_str_bytes
) -> bytes:
236 """Unsigns the given string."""
237 signed_value
= want_bytes(signed_value
)
239 if self
.sep
not in signed_value
:
240 raise BadSignature(f
"No {self.sep!r} found in value")
242 value
, sig
= signed_value
.rsplit(self
.sep
, 1)
244 if self
.verify_signature(value
, sig
):
247 raise BadSignature(f
"Signature {sig!r} does not match", payload
=value
)
249 def validate(self
, signed_value
: _t_str_bytes
) -> bool:
250 """Only validates the given signed value. Returns ``True`` if
251 the signature exists and is valid.
254 self
.unsign(signed_value
)