From dbe57075d386d7474bafc208b654507d9a2d769e Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Sun, 6 Nov 2022 13:48:04 -0700 Subject: Rework to a domains model for better vhosting --- core/signatures.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 core/signatures.py (limited to 'core/signatures.py') diff --git a/core/signatures.py b/core/signatures.py new file mode 100644 index 0000000..bcacb68 --- /dev/null +++ b/core/signatures.py @@ -0,0 +1,48 @@ +import base64 +from typing import Any, Dict, List + +from cryptography.hazmat.primitives import hashes +from django.http import HttpRequest + + +class HttpSignature: + """ + Allows for calculation and verification of HTTP signatures + """ + + @classmethod + def calculate_digest(cls, data, algorithm="sha-256") -> str: + """ + Calculates the digest header value for a given HTTP body + """ + if algorithm == "sha-256": + digest = hashes.Hash(hashes.SHA256()) + digest.update(data) + return "SHA-256=" + base64.b64encode(digest.finalize()).decode("ascii") + else: + raise ValueError(f"Unknown digest algorithm {algorithm}") + + @classmethod + def headers_from_request(cls, request: HttpRequest, header_names: List[str]) -> str: + """ + Creates the to-be-signed header payload from a Django request""" + headers = {} + for header_name in header_names: + if header_name == "(request-target)": + value = f"post {request.path}" + elif header_name == "content-type": + value = request.META["CONTENT_TYPE"] + else: + value = request.META[f"HTTP_{header_name.upper()}"] + headers[header_name] = value + return "\n".join(f"{name.lower()}: {value}" for name, value in headers.items()) + + @classmethod + def parse_signature(cls, signature) -> Dict[str, Any]: + signature_details = {} + for item in signature.split(","): + name, value = item.split("=", 1) + value = value.strip('"') + signature_details[name.lower()] = value + signature_details["headers"] = signature_details["headers"].split() + return signature_details -- cgit v1.2.3