From dd55775a9d650a664c5d569011ed6dc32044f78b Mon Sep 17 00:00:00 2001 From: imperosol Date: Sun, 26 Oct 2025 14:03:03 +0100 Subject: [PATCH] `hmac_hexdigest` util function --- api/templates/api/third_party/auth.jinja | 32 +++++++++++++++++++ core/utils.py | 39 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 api/templates/api/third_party/auth.jinja 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 %} +
+ {% csrf_token %} +

{% trans %}Confidentiality{% endtrans %}

+

+ {% trans trimmed app=third_party_app %} + By ticking this box and clicking on the send button, you + acknowledge and agree to provide {{ app }} with your + first name, last name, nickname and any other information + that was the third party app was explicitly authorized to fetch + and that it must have acknowledged to you, in a complete and accurate manner. + {% endtrans %} +

+

+ {% trans trimmed app=third_party_app, cgu_link=third_party_cgu, sith_cgu_link=sith_cgu %} + The privacy policies of {{ app }} + and of the Students' Association + applies as soon as the form is submitted. + {% endtrans %} +

+
{{ form.cgu_accepted }} {{ form.cgu_accepted.label_tag() }}
+
+

{% trans %}Confirmation of identity{% endtrans %}

+
+ {{ form.is_username_valid }} {{ form.is_username_valid.label_tag() }} +
+ {% for field in form.hidden_fields() %}{{ field }}{% endfor %} + +
+{% 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()