aboutsummaryrefslogtreecommitdiff
path: root/venv/lib/python3.8/site-packages/itsdangerous/signer.py
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
committersotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
commit5bf22fc7e3c392c8bd44315ca2d06d7dca7d084e (patch)
tree8dacb0f195df1c0788d36dd0064f6bbaa3143ede /venv/lib/python3.8/site-packages/itsdangerous/signer.py
parentb832d364da8c2efe09e3f75828caf73c50d01ce3 (diff)
add code for analysis of data
Diffstat (limited to 'venv/lib/python3.8/site-packages/itsdangerous/signer.py')
-rw-r--r--venv/lib/python3.8/site-packages/itsdangerous/signer.py266
1 files changed, 266 insertions, 0 deletions
diff --git a/venv/lib/python3.8/site-packages/itsdangerous/signer.py b/venv/lib/python3.8/site-packages/itsdangerous/signer.py
new file mode 100644
index 0000000..e324dc0
--- /dev/null
+++ b/venv/lib/python3.8/site-packages/itsdangerous/signer.py
@@ -0,0 +1,266 @@
+from __future__ import annotations
+
+import collections.abc as cabc
+import hashlib
+import hmac
+import typing as t
+
+from .encoding import _base64_alphabet
+from .encoding import base64_decode
+from .encoding import base64_encode
+from .encoding import want_bytes
+from .exc import BadSignature
+
+
+class SigningAlgorithm:
+ """Subclasses must implement :meth:`get_signature` to provide
+ signature generation functionality.
+ """
+
+ def get_signature(self, key: bytes, value: bytes) -> bytes:
+ """Returns the signature for the given key and value."""
+ raise NotImplementedError()
+
+ def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool:
+ """Verifies the given signature matches the expected
+ signature.
+ """
+ return hmac.compare_digest(sig, self.get_signature(key, value))
+
+
+class NoneAlgorithm(SigningAlgorithm):
+ """Provides an algorithm that does not perform any signing and
+ returns an empty signature.
+ """
+
+ def get_signature(self, key: bytes, value: bytes) -> bytes:
+ return b""
+
+
+def _lazy_sha1(string: bytes = b"") -> t.Any:
+ """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include
+ SHA-1, in which case the import and use as a default would fail before the
+ developer can configure something else.
+ """
+ return hashlib.sha1(string)
+
+
+class HMACAlgorithm(SigningAlgorithm):
+ """Provides signature generation using HMACs."""
+
+ #: The digest method to use with the MAC algorithm. This defaults to
+ #: SHA1, but can be changed to any other function in the hashlib
+ #: module.
+ default_digest_method: t.Any = staticmethod(_lazy_sha1)
+
+ def __init__(self, digest_method: t.Any = None):
+ if digest_method is None:
+ digest_method = self.default_digest_method
+
+ self.digest_method: t.Any = digest_method
+
+ def get_signature(self, key: bytes, value: bytes) -> bytes:
+ mac = hmac.new(key, msg=value, digestmod=self.digest_method)
+ return mac.digest()
+
+
+def _make_keys_list(
+ secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+) -> list[bytes]:
+ if isinstance(secret_key, (str, bytes)):
+ return [want_bytes(secret_key)]
+
+ return [want_bytes(s) for s in secret_key] # pyright: ignore
+
+
+class Signer:
+ """A signer securely signs bytes, then unsigns them to verify that
+ the value hasn't been changed.
+
+ The secret key should be a random string of ``bytes`` and should not
+ be saved to code or version control. Different salts should be used
+ to distinguish signing in different contexts. See :doc:`/concepts`
+ for information about the security of the secret key and salt.
+
+ :param secret_key: The secret key to sign and verify with. Can be a
+ list of keys, oldest to newest, to support key rotation.
+ :param salt: Extra key to combine with ``secret_key`` to distinguish
+ signatures in different contexts.
+ :param sep: Separator between the signature and value.
+ :param key_derivation: How to derive the signing key from the secret
+ key and salt. Possible values are ``concat``, ``django-concat``,
+ or ``hmac``. Defaults to :attr:`default_key_derivation`, which
+ defaults to ``django-concat``.
+ :param digest_method: Hash function to use when generating the HMAC
+ signature. Defaults to :attr:`default_digest_method`, which
+ defaults to :func:`hashlib.sha1`. Note that the security of the
+ hash alone doesn't apply when used intermediately in HMAC.
+ :param algorithm: A :class:`SigningAlgorithm` instance to use
+ instead of building a default :class:`HMACAlgorithm` with the
+ ``digest_method``.
+
+ .. versionchanged:: 2.0
+ Added support for key rotation by passing a list to
+ ``secret_key``.
+
+ .. versionchanged:: 0.18
+ ``algorithm`` was added as an argument to the class constructor.
+
+ .. versionchanged:: 0.14
+ ``key_derivation`` and ``digest_method`` were added as arguments
+ to the class constructor.
+ """
+
+ #: The default digest method to use for the signer. The default is
+ #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or
+ #: compatible object. Note that the security of the hash alone
+ #: doesn't apply when used intermediately in HMAC.
+ #:
+ #: .. versionadded:: 0.14
+ default_digest_method: t.Any = staticmethod(_lazy_sha1)
+
+ #: The default scheme to use to derive the signing key from the
+ #: secret key and salt. The default is ``django-concat``. Possible
+ #: values are ``concat``, ``django-concat``, and ``hmac``.
+ #:
+ #: .. versionadded:: 0.14
+ default_key_derivation: str = "django-concat"
+
+ def __init__(
+ self,
+ secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
+ salt: str | bytes | None = b"itsdangerous.Signer",
+ sep: str | bytes = b".",
+ key_derivation: str | None = None,
+ digest_method: t.Any | None = None,
+ algorithm: SigningAlgorithm | None = None,
+ ):
+ #: The list of secret keys to try for verifying signatures, from
+ #: oldest to newest. The newest (last) key is used for signing.
+ #:
+ #: This allows a key rotation system to keep a list of allowed
+ #: keys and remove expired ones.
+ self.secret_keys: list[bytes] = _make_keys_list(secret_key)
+ self.sep: bytes = want_bytes(sep)
+
+ if self.sep in _base64_alphabet:
+ raise ValueError(
+ "The given separator cannot be used because it may be"
+ " contained in the signature itself. ASCII letters,"
+ " digits, and '-_=' must not be used."
+ )
+
+ if salt is not None:
+ salt = want_bytes(salt)
+ else:
+ salt = b"itsdangerous.Signer"
+
+ self.salt = salt
+
+ if key_derivation is None:
+ key_derivation = self.default_key_derivation
+
+ self.key_derivation: str = key_derivation
+
+ if digest_method is None:
+ digest_method = self.default_digest_method
+
+ self.digest_method: t.Any = digest_method
+
+ if algorithm is None:
+ algorithm = HMACAlgorithm(self.digest_method)
+
+ self.algorithm: SigningAlgorithm = algorithm
+
+ @property
+ def secret_key(self) -> bytes:
+ """The newest (last) entry in the :attr:`secret_keys` list. This
+ is for compatibility from before key rotation support was added.
+ """
+ return self.secret_keys[-1]
+
+ def derive_key(self, secret_key: str | bytes | None = None) -> bytes:
+ """This method is called to derive the key. The default key
+ derivation choices can be overridden here. Key derivation is not
+ intended to be used as a security method to make a complex key
+ out of a short password. Instead you should use large random
+ secret keys.
+
+ :param secret_key: A specific secret key to derive from.
+ Defaults to the last item in :attr:`secret_keys`.
+
+ .. versionchanged:: 2.0
+ Added the ``secret_key`` parameter.
+ """
+ if secret_key is None:
+ secret_key = self.secret_keys[-1]
+ else:
+ secret_key = want_bytes(secret_key)
+
+ if self.key_derivation == "concat":
+ return t.cast(bytes, self.digest_method(self.salt + secret_key).digest())
+ elif self.key_derivation == "django-concat":
+ return t.cast(
+ bytes, self.digest_method(self.salt + b"signer" + secret_key).digest()
+ )
+ elif self.key_derivation == "hmac":
+ mac = hmac.new(secret_key, digestmod=self.digest_method)
+ mac.update(self.salt)
+ return mac.digest()
+ elif self.key_derivation == "none":
+ return secret_key
+ else:
+ raise TypeError("Unknown key derivation method")
+
+ def get_signature(self, value: str | bytes) -> bytes:
+ """Returns the signature for the given value."""
+ value = want_bytes(value)
+ key = self.derive_key()
+ sig = self.algorithm.get_signature(key, value)
+ return base64_encode(sig)
+
+ def sign(self, value: str | bytes) -> bytes:
+ """Signs the given string."""
+ value = want_bytes(value)
+ return value + self.sep + self.get_signature(value)
+
+ def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool:
+ """Verifies the signature for the given value."""
+ try:
+ sig = base64_decode(sig)
+ except Exception:
+ return False
+
+ value = want_bytes(value)
+
+ for secret_key in reversed(self.secret_keys):
+ key = self.derive_key(secret_key)
+
+ if self.algorithm.verify_signature(key, value, sig):
+ return True
+
+ return False
+
+ def unsign(self, signed_value: str | bytes) -> bytes:
+ """Unsigns the given string."""
+ signed_value = want_bytes(signed_value)
+
+ if self.sep not in signed_value:
+ raise BadSignature(f"No {self.sep!r} found in value")
+
+ value, sig = signed_value.rsplit(self.sep, 1)
+
+ if self.verify_signature(value, sig):
+ return value
+
+ raise BadSignature(f"Signature {sig!r} does not match", payload=value)
+
+ def validate(self, signed_value: str | bytes) -> bool:
+ """Only validates the given signed value. Returns ``True`` if
+ the signature exists and is valid.
+ """
+ try:
+ self.unsign(signed_value)
+ return True
+ except BadSignature:
+ return False