Enforce file access permissions

This commit is contained in:
2026-01-04 23:48:52 +01:00
parent 49c8d804d6
commit ede8741473
3 changed files with 50 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix
__version__ = "0.19.6"
__version__ = "0.19.7"
__version__ += git_suffix(__file__)

View File

@@ -21,17 +21,22 @@ from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from ram.views import UploadImage
from ram.views import UploadImage, DownloadFile
from portal.views import Render404
handler404 = Render404.as_view()
urlpatterns = [
path("", lambda r: redirect("portal/")),
path("admin/", admin.site.urls),
path("tinymce/", include("tinymce.urls")),
path("tinymce/upload_image", UploadImage.as_view(), name="upload_image"),
path(
"media/files/<path:filename>",
DownloadFile.as_view(),
name="download_file",
),
path("portal/", include("portal.urls")),
path("admin/", admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# Enable the "/dcc" routing only if the "driver" app is active
@@ -55,6 +60,7 @@ if settings.DEBUG:
if settings.REST_ENABLED:
from django.views.generic import TemplateView
from rest_framework.schemas import get_schema_view
urlpatterns += [
path(
"swagger/",

View File

@@ -5,19 +5,25 @@ import posixpath
from pathlib import Path
from PIL import Image, UnidentifiedImageError
from django.views import View
from django.apps import apps
from django.conf import settings
from django.http import (
Http404,
HttpResponseBadRequest,
HttpResponseForbidden,
FileResponse,
JsonResponse,
)
from django.views import View
from django.utils.text import slugify as slugify
from django.utils.encoding import smart_str
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.pagination import LimitOffsetPagination
from ram.models import PrivateDocument
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 10
@@ -67,3 +73,37 @@ class UploadImage(View):
),
}
)
class DownloadFile(View):
def get(self, request, filename, disposition="inline"):
# Clean up the filename to prevent directory traversal attacks
filename = os.path.basename(filename)
# Find a document where the stored file name matches
# Find all models inheriting from PublishableFile
for model in apps.get_models():
if issubclass(model, PrivateDocument) and not model._meta.abstract:
try:
doc = model.objects.get(file__endswith=filename)
if doc.private and not request.user.is_staff:
break
file_path = doc.file.path
if not os.path.exists(file_path):
break
response = FileResponse(
open(file_path, "rb"), as_attachment=True
)
response["Content-Disposition"] = (
'{}; filename="{}"'.format(
disposition,
smart_str(os.path.basename(file_path))
)
)
return response
except model.DoesNotExist:
continue
raise Http404("File not found")