import base64 import hashlib import time from urllib.parse import quote, urlencode from django.conf import settings from django.http import HttpResponseRedirect def signed_media_redirect(relative_path, *, download=False, lifetime=300): """Create an Nginx secure_link URL after Django has authorized the request.""" safe_path = quote(str(relative_path).replace("\\", "/").lstrip("/"), safe="/") uri = f"/protected-media/{safe_path}" expires = int(time.time()) + lifetime source = f"{expires}{uri} {settings.MEDIA_SIGNING_SECRET}".encode() digest = hashlib.md5(source, usedforsecurity=False).digest() signature = base64.urlsafe_b64encode(digest).rstrip(b"=").decode() query = {"md5": signature, "expires": expires} if download: query["download"] = "1" return HttpResponseRedirect(f"{uri}?{urlencode(query)}") def attachment_response(attachment, *, download=False): """Deliver authorized bytes; confidential responses never use bearer URLs.""" import mimetypes from django.http import FileResponse if settings.USE_NGINX_MEDIA and not attachment.relative_path.startswith("dispatch-responses/"): return signed_media_redirect(attachment.relative_path, download=download) content_type = attachment.mime_type or mimetypes.guess_type(attachment.original_name)[0] or "application/octet-stream" response = FileResponse(attachment.file.open("rb"), content_type=content_type, as_attachment=download, filename=attachment.original_name) response["X-Content-Type-Options"] = "nosniff" return response