package handlers import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/treytartt/honeydue-api/internal/config" "github.com/treytartt/honeydue-api/internal/services" ) // newTestStorageService creates a StorageService with a known upload directory for testing. // It does NOT call NewStorageService because that creates directories on disk. // Instead, it directly constructs the struct with only what resolveFilePath needs. func newTestStorageService(uploadDir string) *services.StorageService { cfg := &config.StorageConfig{ UploadDir: uploadDir, BaseURL: "/uploads", MaxFileSize: 10 * 1024 * 1024, AllowedTypes: "image/jpeg,image/png", } // Use the exported constructor helper that skips directory creation (for tests) return services.NewStorageServiceForTest(cfg) } func TestResolveFilePath_NormalPath_Works(t *testing.T) { storageSvc := newTestStorageService("/var/uploads") h := NewMediaHandler(nil, nil, nil, storageSvc) result := h.resolveFilePath("images/photo.jpg") require.NotEmpty(t, result) assert.Equal(t, "/var/uploads/images/photo.jpg", result) } func TestResolveFilePath_LegacyUploadPath_Works(t *testing.T) { storageSvc := newTestStorageService("/var/uploads") h := NewMediaHandler(nil, nil, nil, storageSvc) result := h.resolveFilePath("/uploads/images/photo.jpg") require.NotEmpty(t, result) assert.Equal(t, "/var/uploads/images/photo.jpg", result) } func TestResolveFilePath_DotDotTraversal_Blocked(t *testing.T) { storageSvc := newTestStorageService("/var/uploads") h := NewMediaHandler(nil, nil, nil, storageSvc) tests := []struct { name string storedURL string }{ {"simple dotdot", "../etc/passwd"}, {"nested dotdot", "../../etc/shadow"}, {"embedded dotdot", "images/../../etc/passwd"}, {"legacy prefix with dotdot", "/uploads/../../../etc/passwd"}, {"deep dotdot", "a/b/c/../../../../etc/passwd"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := h.resolveFilePath(tt.storedURL) assert.Empty(t, result, "path traversal should return empty string for: %s", tt.storedURL) }) } } func TestResolveFilePath_EmptyURL_ReturnsEmpty(t *testing.T) { storageSvc := newTestStorageService("/var/uploads") h := NewMediaHandler(nil, nil, nil, storageSvc) result := h.resolveFilePath("") assert.Empty(t, result) }