You've already forked openaccounting-server
forked from cybercinch/openaccounting-server
- Add JWT-based secure file access for local storage with 1-hour expiry - Implement GORM repository methods for attachment CRUD operations - Add secure file serving endpoint with token validation - Update storage interface to support user context in URL generation - Add comprehensive security features including path traversal protection - Update documentation with security model and configuration examples - Add utility functions for hex/byte conversion and UUID validation - Configure secure file permissions (0600) for uploaded files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestNewStorage(t *testing.T) {
|
|
t.Run("Local Storage", func(t *testing.T) {
|
|
config := Config{
|
|
Backend: "local",
|
|
Local: LocalConfig{
|
|
RootDir: t.TempDir(),
|
|
},
|
|
}
|
|
|
|
storage, err := NewStorage(config)
|
|
assert.NoError(t, err)
|
|
assert.IsType(t, &LocalStorage{}, storage)
|
|
})
|
|
|
|
t.Run("Default to Local Storage", func(t *testing.T) {
|
|
config := Config{
|
|
// No backend specified
|
|
Local: LocalConfig{
|
|
RootDir: t.TempDir(),
|
|
},
|
|
}
|
|
|
|
storage, err := NewStorage(config)
|
|
assert.NoError(t, err)
|
|
assert.IsType(t, &LocalStorage{}, storage)
|
|
})
|
|
|
|
t.Run("S3 Storage", func(t *testing.T) {
|
|
config := Config{
|
|
Backend: "s3",
|
|
S3: S3Config{
|
|
Region: "us-east-1",
|
|
Bucket: "test-bucket",
|
|
},
|
|
}
|
|
|
|
// This might succeed if AWS credentials are available via IAM roles or env vars
|
|
// Let's just check that we get an S3Storage instance or an error
|
|
storage, err := NewStorage(config)
|
|
if err != nil {
|
|
// If it fails, that's expected in test environments without AWS access
|
|
assert.Nil(t, storage)
|
|
} else {
|
|
// If it succeeds, we should get an S3Storage instance
|
|
assert.IsType(t, &S3Storage{}, storage)
|
|
}
|
|
})
|
|
|
|
t.Run("Invalid Backend", func(t *testing.T) {
|
|
config := Config{
|
|
Backend: "invalid",
|
|
}
|
|
|
|
storage, err := NewStorage(config)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, storage)
|
|
})
|
|
|
|
t.Run("Unsupported Backend", func(t *testing.T) {
|
|
config := Config{
|
|
Backend: "unsupported",
|
|
}
|
|
|
|
storage, err := NewStorage(config)
|
|
assert.Error(t, err)
|
|
assert.IsType(t, &UnsupportedBackendError{}, err)
|
|
assert.Nil(t, storage)
|
|
assert.Contains(t, err.Error(), "unsupported")
|
|
})
|
|
}
|
|
|
|
func TestStorageErrors(t *testing.T) {
|
|
t.Run("UnsupportedBackendError", func(t *testing.T) {
|
|
err := &UnsupportedBackendError{Backend: "ftp"}
|
|
assert.Equal(t, "unsupported storage backend: ftp", err.Error())
|
|
})
|
|
|
|
t.Run("FileNotFoundError", func(t *testing.T) {
|
|
err := &FileNotFoundError{Path: "missing.txt"}
|
|
assert.Equal(t, "file not found: missing.txt", err.Error())
|
|
})
|
|
|
|
t.Run("InvalidPathError", func(t *testing.T) {
|
|
err := &InvalidPathError{Path: "../../../etc/passwd"}
|
|
assert.Equal(t, "invalid path: ../../../etc/passwd", err.Error())
|
|
})
|
|
} |