Skip to content

fix: serve attachments with uppercase extensions - #1637

Open
breken-ai wants to merge 1 commit into
apache:devfrom
breken-ai:fix/attachment-uppercase-extension
Open

breken-ai wants to merge 1 commit into
apache:devfrom
breken-ai:fix/attachment-uppercase-extension

Conversation

@breken-ai

Copy link
Copy Markdown

Fixes: n/a (no existing issue; details below)

Proposed Changes

  • Bug: on Linux (or any case-sensitive filesystem), an attachment whose name has an uppercase extension can't be downloaded. Upload Report.PDF or Scan.ZIP and the post shows a link, but clicking it redirects to /404. Files from Windows, scanners and cameras often have uppercase extensions like this.
  • Cause: UploadPostAttachment lowercases the extension when it saves the file (fileExt := strings.ToLower(path.Ext(...)), so the file becomes files/post/<hash>.pdf), but it puts the original name in the link (/uploads/files/post/<hash>/Report.PDF). The download route in internal/router/static_router.go rebuilt the local name from the link's extension without lowercasing it, so it looked for <hash>.PDF. That file doesn't exist, so CheckFileExist failed and the route redirected to /404. On macOS/Windows default filesystems the lookup is case-insensitive, which hides the bug in local development.
  • Fix: one line. attachmentFileLocalPath now lowercases the extension, matching what the uploader stores. The download filename sent in Content-Disposition still uses the original Report.PDF, and the path traversal checks are unchanged.
  • Tests (internal/router/static_router_test.go):
    • TestAttachmentFileLocalPathLowercasesExtension checks that /hash/Report.PDF resolves to files/post/hash.pdf. This check doesn't depend on the filesystem.
    • TestAttachmentDownloadWithUppercaseExtension registers the real static router on a gin engine, stores hash.pdf the way the uploader does, and requests /uploads/files/post/hash/Report.PDF.
    • On dev @ 6c00c788, running on a case-sensitive volume, both fail: the path is .../hash.PDF and the response is 302 Location: /404. With the fix, all router tests pass. The existing traversal test is unchanged and still passes.
  • Checks: go test ./internal/router/, go vet, gofmt, and golangci-lint v2.6.2 (the repo's .golangci.yaml) report 0 issues.

This bug was found and the fix and tests were written with AI assistance (Claude); I reviewed the change and ran the tests above.

UploadPostAttachment stores an upload with a lowercased extension
(Report.PDF is saved as files/post/<hash>.pdf) but keeps the original
name in the download link. The download route rebuilt the local name
from the link's extension as typed, so on a case-sensitive filesystem
it looked for <hash>.PDF, did not find it, and redirected to /404.
Lowercase the extension when resolving the local path.

Generated-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant