Skip to content

feat: profile photo upload for community profiles#1645

Closed
bokelley wants to merge 2 commits into
mainfrom
bokelley/profile-photo-upload
Closed

feat: profile photo upload for community profiles#1645
bokelley wants to merge 2 commits into
mainfrom
bokelley/profile-photo-upload

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Summary

Changes

  • New migration (323_avatar_upload.sql): adds avatar_data BYTEA and avatar_mime_type columns to users table with CHECK constraint
  • New routes (server/src/routes/avatar.ts): upload, serve, and delete endpoints with magic byte validation, rate limiting, and security headers
  • Updated UI (profile-edit.html): circular preview, upload button, remove button, status feedback
  • Tests: 8 unit tests covering happy paths, content validation, and rejection cases

Security

  • Magic byte validation prevents MIME spoofing (stored XSS mitigation)
  • X-Content-Type-Options: nosniff and Content-Disposition: inline headers on served images
  • Rate limited: 10 uploads per 15 minutes per user
  • MIME type derived from file content, not client-supplied Content-Type
  • DB CHECK constraint restricts mime_type to image/jpeg or image/png
  • Multer errors return JSON responses (not raw HTML)

Test plan

  • Upload a JPEG photo and verify preview updates
  • Upload a PNG photo and verify preview updates
  • Remove photo and verify placeholder returns
  • Verify file size rejection (>2MB)
  • Verify non-image file rejection
  • Save profile after upload and confirm avatar persists
  • Visit profile page and confirm avatar displays

🤖 Generated with Claude Code

bokelley and others added 2 commits March 23, 2026 14:59
Replace the avatar URL text input with a file upload UI on the community
profile edit page. Members can now upload JPEG/PNG photos (max 2MB)
directly rather than needing to paste an external URL.

- New avatar routes: upload, serve, and delete endpoints
- Magic byte validation to prevent MIME spoofing
- Rate limiting (10 uploads / 15 min)
- Security headers (nosniff, Content-Disposition)
- DB migration adds avatar_data BYTEA column with CHECK constraint

Resolves Escalation #137

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bokelley

Copy link
Copy Markdown
Contributor Author

Closing in favor of connecting the existing portrait system to community profiles instead of building a separate photo upload pipeline.

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