Add secure media access control with authenticated proxy endpoints
- Add MediaHandler with token-based proxy endpoints for serving media: - GET /api/media/document/:id - GET /api/media/document-image/:id - GET /api/media/completion-image/:id - Add MediaURL fields to response DTOs for documents and task completions - Add FindImageByID and FindCompletionImageByID repository methods - Preload Completions.Images in all task queries for proper media URLs - Remove public /uploads static file serving for security - Verify residence access before serving any media files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -54,10 +54,12 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
// Health check endpoint (no auth required)
|
||||
r.GET("/api/health/", healthCheck)
|
||||
|
||||
// Serve static files from uploads directory
|
||||
if cfg.Storage.UploadDir != "" {
|
||||
r.Static("/uploads", cfg.Storage.UploadDir)
|
||||
}
|
||||
// NOTE: Public static file serving removed for security.
|
||||
// All uploaded media is now served through authenticated proxy endpoints:
|
||||
// - GET /api/media/document/:id
|
||||
// - GET /api/media/document-image/:id
|
||||
// - GET /api/media/completion-image/:id
|
||||
// These endpoints verify the user has access to the residence before serving files.
|
||||
|
||||
// Initialize repositories
|
||||
userRepo := repositories.NewUserRepository(deps.DB)
|
||||
@@ -104,8 +106,10 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
|
||||
// Initialize upload handler (if storage service is available)
|
||||
var uploadHandler *handlers.UploadHandler
|
||||
var mediaHandler *handlers.MediaHandler
|
||||
if deps.StorageService != nil {
|
||||
uploadHandler = handlers.NewUploadHandler(deps.StorageService)
|
||||
mediaHandler = handlers.NewMediaHandler(documentRepo, taskRepo, residenceRepo, deps.StorageService)
|
||||
}
|
||||
|
||||
// Set up admin routes (separate auth system)
|
||||
@@ -141,6 +145,11 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
|
||||
if uploadHandler != nil {
|
||||
setupUploadRoutes(protected, uploadHandler)
|
||||
}
|
||||
|
||||
// Media routes (authenticated media serving)
|
||||
if mediaHandler != nil {
|
||||
setupMediaRoutes(protected, mediaHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,3 +363,13 @@ func setupUploadRoutes(api *gin.RouterGroup, uploadHandler *handlers.UploadHandl
|
||||
uploads.DELETE("/", uploadHandler.DeleteFile)
|
||||
}
|
||||
}
|
||||
|
||||
// setupMediaRoutes configures authenticated media serving routes
|
||||
func setupMediaRoutes(api *gin.RouterGroup, mediaHandler *handlers.MediaHandler) {
|
||||
media := api.Group("/media")
|
||||
{
|
||||
media.GET("/document/:id", mediaHandler.ServeDocument)
|
||||
media.GET("/document-image/:id", mediaHandler.ServeDocumentImage)
|
||||
media.GET("/completion-image/:id", mediaHandler.ServeCompletionImage)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user