Repository navigation
Store sound uploads under a generated name (#699) - #982
Merged
Merged
Conversation
Sound was the last media field writing the user's own filename straight to storage: objects already land in objects/<pk>/source.<ext> and markers are renamed to markers/<pk>/original.<ext> by generate_marker_variants. Sound.file now routes through sound_file_path(), which writes sounds/<uuid>.<ext>. A uuid rather than the <pk>/<role> layout because the primary key does not exist yet when the path is generated for a new row. The original name was already kept on Sound.file_name_original. Closes #699 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXUw7kyELDu8ycGQxtaFbb
The Linter workflow's `ruff format --diff src/` step failed on this file: the SimpleUploadedFile call exceeded the line limit. No behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXUw7kyELDu8ycGQxtaFbb
This was referenced Sep 17, 2026
Member
Author
|
@pablodiegoss você pode revisar este PR quando tiver um tempo? Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
@pablodiegoss's reason for keeping #699 open is the one that matters, and it's stronger than the S3-escaping framing the issue opens with: a user-supplied filename becomes part of a public URL, so nothing stops someone uploading a file whose name is NSFW, political or religious and having the platform serve it. That is the argument this PR is built on.
Checking what is actually stored today, most of the surface is already covered:
Object.sourceobjects/<pk>/source.<ext>object_source_path)Marker.sourcemarkers/<pk>/original.<ext>Sound.filesounds/<the user's filename>So this PR is narrow on purpose:
Sound.filenow routes throughsound_file_path(), which writessounds/<uuid>.<ext>. A uuid rather than the<pk>/<role>layout because the primary key does not exist yet when Django generates the upload path for a new row — and, as the issue notes, it also removes collisions.Sound.file_name_originalalready existed and is already populated bySoundForm.save(), so the "keep the original name" half of the issue needed nothing.Resolves (Issues)
Closes #699
General tasks performed
sound_file_path()next to the existingobject_*_pathhelpers, lowercasing the extension and tolerating a name without one.Sound.fileat it; migration0045_alter_sound_file_alter_soundevent_filecovers the model and its pghistory event model.src/core/tests/test_sound_upload_path.py— a hostile filename (Música #1 (versão final?) 100%.mp3) never reaching storage, the original name still recorded, two identical names not colliding, and the helper's extension handling.A related gap, not fixed here
Markers are only eventually safe. The upload first lands under the user's own filename, and
marker_utils.py:97-101deletes it afterwards — inside a bareexcept Exception: pass. If that delete ever fails (S3 permissions, a transient error), the user-named object stays in public storage and nobody is told. Same privacy exposure, different code path; worth making that failure loud, but it is outside this PR's diff.Deliberately not included
The backfill. The issue asks for "a migration to rename all the objects in the current database". That renames live S3 objects, and a half-applied run leaves rows pointing at files that no longer exist. It wants to be a resumable management command rather than a migration, and an ops decision about the window — so I left it out. Existing rows keep working untouched; only new uploads take the new path.
Verification: full suite passes, 277 passed. Reverting
upload_toto the old string makestest_hostile_filename_never_reaches_storagefail, so the test does exercise the change.makemigrations --check --dry-runreports no changes; both CI lint steps are clean.Have you confirmed the application builds locally without error? See here.
🤖 Generated with Claude Code
https://claude.ai/code/session_01HXUw7kyELDu8ycGQxtaFbb
Generated by Claude Code