feat: implement secure file upload system with JWT authentication

- 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>
This commit is contained in:
2025-07-03 15:45:25 +12:00
parent b2b77eb4da
commit 8b6ba74ce9
19 changed files with 546 additions and 43 deletions

View File

@@ -40,6 +40,7 @@ func main() {
viper.BindEnv("Storage.backend", "OA_STORAGE_BACKEND")
viper.BindEnv("Storage.local.root_dir", "OA_STORAGE_LOCAL_ROOTDIR")
viper.BindEnv("Storage.local.base_url", "OA_STORAGE_LOCAL_BASEURL")
viper.BindEnv("Storage.local.signing_key", "OA_STORAGE_LOCAL_SIGNINGKEY")
viper.BindEnv("Storage.s3.region", "OA_STORAGE_S3_REGION")
viper.BindEnv("Storage.s3.bucket", "OA_STORAGE_S3_BUCKET")
viper.BindEnv("Storage.s3.prefix", "OA_STORAGE_S3_PREFIX")
@@ -59,6 +60,7 @@ func main() {
viper.SetDefault("Storage.backend", "local")
viper.SetDefault("Storage.local.root_dir", "./uploads")
viper.SetDefault("Storage.local.base_url", "")
viper.SetDefault("Storage.local.signing_key", "") // Will auto-generate if empty
// Read configuration
err := viper.ReadInConfig()
@@ -141,6 +143,9 @@ func main() {
log.Fatal(fmt.Errorf("failed to initialize storage backend: %s", err.Error()))
}
// Initialize secure file server with signing key for local storage
api.InitSecureFileServer(config.Storage.Local.SigningKey)
app, err := api.Init(config.ApiPrefix)
if err != nil {
log.Fatal(fmt.Errorf("failed to create api instance with: %s", err.Error()))