diff --git a/api/templates/api/third_party/auth.jinja b/api/templates/api/third_party/auth.jinja new file mode 100644 index 00000000..e4e9e4f6 --- /dev/null +++ b/api/templates/api/third_party/auth.jinja @@ -0,0 +1,32 @@ +{% extends "core/base.jinja" %} + +{% block content %} +
+{% endblock %} \ No newline at end of file diff --git a/core/utils.py b/core/utils.py index 30c0116d..1adf50ec 100644 --- a/core/utils.py +++ b/core/utils.py @@ -12,12 +12,15 @@ # OR WITHIN THE LOCAL FILE "LICENSE" # # +from __future__ import annotations +import hmac from datetime import date, timedelta # Image utils from io import BytesIO from typing import TYPE_CHECKING, Final +from urllib.parse import urlencode import PIL from django.conf import settings @@ -25,6 +28,15 @@ from django.core.files.base import ContentFile from django.utils.timezone import localdate from PIL.Image import Image, Resampling +if TYPE_CHECKING: + from _hashlib import HASH + from collections.abc import Buffer, Mapping, Sequence + from typing import Any, Callable, Final + + from django.core.files.uploadedfile import UploadedFile + from django.http import HttpRequest + + if TYPE_CHECKING: from django.core.files.uploadedfile import UploadedFile from django.http import HttpRequest @@ -190,3 +202,30 @@ def get_client_ip(request: HttpRequest) -> str | None: return ip return None + + +def hmac_hexdigest( + key: str | bytes, + data: Mapping[str, Any] | Sequence[tuple[str, Any]], + digest: str | Callable[[Buffer], HASH] = "sha256", +) -> str: + """Return the hexdigest of the signature of the given data. + + Args: + key: the HMAC key used for the signature + data: the data to sign + digest: a PEP247 hashing algorithm + + Examples: + ```python + data = { + "foo": 5, + "bar": "somevalue", + } + hmac_key = secrets.token_hex(64) + signature = hmac_hexdigest(hmac_key, data, "sha512") + ``` + """ + if isinstance(key, str): + key = key.encode() + return hmac.digest(key, urlencode(data).encode(), digest).hex()