🔒️(backend) prevent accessing files if they are not ready

With the addition of the ANALYSING state
files could be accessed in the short time they
were in that state.
We now require files to be in ready.

Also adds missing frontend types (no impact).
This commit is contained in:
Florent Chehab
2026-06-03 15:15:24 +02:00
parent 22b2e6bd1e
commit c79984a883
7 changed files with 16 additions and 11 deletions
+1
View File
@@ -20,6 +20,7 @@ and this project adheres to
### Fixed
- 🔇(summary) make ffmpeg quiet #1404
- 🔒️(backend) prevent accessing files if they are not ready #1395
## [1.18.0] - 2026-06-03
+3 -3
View File
@@ -177,7 +177,7 @@ class FileAdmin(admin.ModelAdmin):
"hard_deleted_at",
"description",
"malware_detection_info",
"is_pending_upload",
"is_ready",
"preview_url",
"extension",
"key_base",
@@ -226,7 +226,7 @@ class FileAdmin(admin.ModelAdmin):
_("Derived info"),
{
"fields": (
"is_pending_upload",
"is_ready",
"extension",
"key_base",
"file_key",
@@ -240,7 +240,7 @@ class FileAdmin(admin.ModelAdmin):
@admin.display(description=_("File preview"))
def preview_url(self, obj):
"""Return a clickable preview URL for the file."""
if obj.is_pending_upload:
if not obj.is_ready:
return "-"
url = generate_download_file_url(obj, expires_in=60 * 60)
+1 -1
View File
@@ -456,7 +456,7 @@ class ListFileSerializer(serializers.ModelSerializer):
def get_url(self, obj):
"""Return the URL of the file."""
if obj.is_pending_upload:
if not obj.is_ready:
return None
return f"{settings.MEDIA_BASE_URL}{settings.MEDIA_URL}{quote(obj.file_key)}"
+1 -1
View File
@@ -1417,7 +1417,7 @@ class FileViewSet(
request, MEDIA_STORAGE_URL_PATTERN
)
if file.is_pending_upload:
if not file.is_ready:
logger.warning("File '%s' is not ready", file.id)
raise drf_exceptions.PermissionDenied()
+3 -3
View File
@@ -925,9 +925,9 @@ class File(BaseModel):
return super().delete(using, keep_parents)
@property
def is_pending_upload(self):
"""Return whether the file is in a pending upload state"""
return self.upload_state == FileUploadStateChoices.PENDING
def is_ready(self):
"""Return whether the file is in a ready upload state"""
return self.upload_state == FileUploadStateChoices.READY
@property
def extension(self):
@@ -86,7 +86,11 @@ def test_api_files_media_get_own():
assert response.content.decode("utf-8") == "my prose"
def test_api_files_media_auth_file_pending():
@pytest.mark.parametrize(
"rejecting_status",
[models.FileUploadStateChoices.PENDING, models.FileUploadStateChoices.ANALYZING],
)
def test_api_files_media_auth_rejects(rejecting_status):
"""
Users who have a specific access to an file, whatever the role, should not be able to
retrieve related attachments if the file is not ready.
@@ -97,7 +101,7 @@ def test_api_files_media_auth_file_pending():
file = factories.FileFactory(
type=models.FileTypeChoices.BACKGROUND_IMAGE,
upload_state=models.FileUploadStateChoices.PENDING,
upload_state=rejecting_status,
creator=user,
)
+1 -1
View File
@@ -5,7 +5,7 @@ export type ApiFileCreator = {
}
export type ApiFileType = 'background_image'
export type ApiFileUploadState = 'pending' | 'ready'
export type ApiFileUploadState = 'pending' | 'analyzing' | 'ready'
export type ApiFileItem = {
id: string // UUID