Skip to content

Instantly share code, notes, and snippets.

@usmanm
Last active October 24, 2024 00:46
Show Gist options
  • Select an option

  • Save usmanm/93c323c333ed2a89a682a03b5d3e903e to your computer and use it in GitHub Desktop.

Select an option

Save usmanm/93c323c333ed2a89a682a03b5d3e903e to your computer and use it in GitHub Desktop.
import hashlib
import hmac
import json
from urllib.parse import urlparse, urlunparse
from django.http import HttpRequest
def verify_signature(signing_key: str, request: HttpRequest, max_delay: int = 30) -> bool:
"""
Verify the signature of an incoming request using the provided signing key.
Args:
signing_key (str): The key used to sign the request from Operator.
request (Request): The incoming request to be verified.
Returns:
bool: True if the signature is valid, False otherwise.
"""
headers = request.headers
x_timestamp = headers.get("X-Timestamp")
if not x_timestamp:
return False
# Is the request too old?
now = time.time()
if now - int(x_timestamp) > max_delay:
return False
x_signature = headers.get("X-Signature")
if not x_signature:
return False
x_idempotency_key = headers.get("X-Idempotency-Key")
if not x_idempotency_key:
return False
# Get the URL without query params.
absolute_url = request.build_absolute_uri()
parsed_url = urlparse(absolute_url)
url_without_query = urlunparse(parsed_url._replace(query=""))
# Determine the content based on the request method.
if request.method == "GET":
# Note that we sort the query params before encoding to ensure that the signature is
# consistent.
content = json.dumps(request.GET, sort_keys=True)
elif request.method == "POST":
content = request.body.decode("utf-8")
else:
return False
# Construct the payload to verify.
payload = f"{url_without_query}:{x_idempotency_key}:{x_timestamp}:{content}"
expected_signature = hmac.new(signing_key.encode("utf-8"), payload.encode("utf-8"), hashlib.sha256).hexdigest()
# Verify the signature. Using compare_digest is important for security, since it prevents
# timing attacks.
return hmac.compare_digest(x_signature, expected_signature)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment