Total rebrand across all Go API source files: - Go module path: casera-api -> honeydue-api - All imports updated (130+ files) - Docker: containers, images, networks renamed - Email templates: support email, noreply, icon URL - Domains: casera.app/mycrib.treytartt.com -> honeyDue.treytartt.com - Bundle IDs: com.tt.casera -> com.tt.honeyDue - IAP product IDs updated - Landing page, admin panel, config defaults - Seeds, CI workflows, Makefile, docs - Database table names preserved (no migration needed) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
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)
|
|
}
|