From ae63a5af647c8865b96e6e50dda1ea9d29b5bd0b Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Mon, 18 May 2026 14:25:23 +0300 Subject: [PATCH] fix: x-accell headers on uploaded poster (#1526) --- cms/version.py | 2 +- files/views/media_auth.py | 37 ++++++++++++++++++++++++++++++++++++- setup.cfg | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cms/version.py b/cms/version.py index 3bbed43f..589e913c 100644 --- a/cms/version.py +++ b/cms/version.py @@ -1 +1 @@ -VERSION = "8.1.0" +VERSION = "8.1.1" diff --git a/files/views/media_auth.py b/files/views/media_auth.py index 7c54d0c0..663997f8 100644 --- a/files/views/media_auth.py +++ b/files/views/media_auth.py @@ -1,7 +1,9 @@ import re +from urllib.parse import unquote from django.conf import settings from django.core.cache import cache +from django.db.models import Q from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_GET @@ -10,6 +12,7 @@ from ..methods import is_mediacms_editor from ..models import Media UID_RE = re.compile(r"[0-9a-f]{32}") +THUMBNAILS_PREFIX = "original/thumbnails/" def _ttl(): @@ -23,6 +26,32 @@ def _extract_uid(uri): return match.group(0) if match else None +def _relpath_from_uri(uri): + path = unquote(uri.split("?", 1)[0]) + media_url = settings.MEDIA_URL + if path.startswith(media_url): + return path[len(media_url) :] + return None + + +def _lookup_uid_by_path(relpath): + path_key = f"xaccel:path:{relpath}" + cached = cache.get(path_key) + if cached is not None: + return cached or None + + parts = relpath.split("/", 4) + if len(parts) < 5 or parts[2] != "user": + cache.set(path_key, "", _ttl()) + return None + username = parts[3] + + row = Media.objects.filter(user__username=username).filter(Q(uploaded_thumbnail=relpath) | Q(uploaded_poster=relpath)).values("uid").first() + uid_hex = row["uid"].hex if row else "" + cache.set(path_key, uid_hex, _ttl()) + return uid_hex or None + + def _lookup_state(uid): """Return (state, owner_id) for a uid, or (None, None) if missing. @@ -76,7 +105,13 @@ def media_auth(request): uri = request.META.get("HTTP_X_ORIGINAL_URI", "") uid = _extract_uid(uri) if not uid: - return HttpResponse(status=403) + # User-uploaded thumbnails/posters don't have the uid in the filename. + # Fall back to a per-path lookup, scoped to /original/thumbnails/. + relpath = _relpath_from_uri(uri) + if relpath and relpath.startswith(THUMBNAILS_PREFIX): + uid = _lookup_uid_by_path(relpath) + if not uid: + return HttpResponse(status=403) user = request.user cache_key = f"xaccel:auth:{uid}:{user.id if user.is_authenticated else 'anon'}" diff --git a/setup.cfg b/setup.cfg index de959b64..e6e6f3e9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,4 +2,4 @@ exclude = .git,*migrations* max-line-length = 119 #ignore=F401,F403,E501,W503 -ignore=E501 +ignore=E501,E203