refactor backend packages and global db service
This commit is contained in:
45
backend/internal/logic/files/service.go
Normal file
45
backend/internal/logic/files/service.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
root string
|
||||
}
|
||||
|
||||
type StoredFile struct {
|
||||
OriginalName string
|
||||
RelativePath string
|
||||
AbsolutePath string
|
||||
}
|
||||
|
||||
func NewService(root string) *Service {
|
||||
return &Service{root: root}
|
||||
}
|
||||
|
||||
func (s *Service) Save(projectID uint, originalName string, content io.Reader) (StoredFile, error) {
|
||||
cleanName := filepath.Base(strings.ReplaceAll(strings.TrimSpace(originalName), "\\", "/"))
|
||||
if cleanName == "." || cleanName == "" {
|
||||
cleanName = "upload.bin"
|
||||
}
|
||||
relative := filepath.ToSlash(filepath.Join("projects", fmt.Sprint(projectID), fmt.Sprintf("%d-%s", time.Now().UnixNano(), cleanName)))
|
||||
absolute := filepath.Join(s.root, filepath.FromSlash(relative))
|
||||
if err := os.MkdirAll(filepath.Dir(absolute), 0o755); err != nil {
|
||||
return StoredFile{}, err
|
||||
}
|
||||
file, err := os.Create(absolute)
|
||||
if err != nil {
|
||||
return StoredFile{}, err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := io.Copy(file, content); err != nil {
|
||||
return StoredFile{}, err
|
||||
}
|
||||
return StoredFile{OriginalName: cleanName, RelativePath: relative, AbsolutePath: absolute}, nil
|
||||
}
|
||||
29
backend/internal/logic/files/service_test.go
Normal file
29
backend/internal/logic/files/service_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSaveStoresFileUnderProjectDirectory(t *testing.T) {
|
||||
service := NewService(t.TempDir())
|
||||
|
||||
stored, err := service.Save(12, "brief.md", strings.NewReader("hello"))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "brief.md", stored.OriginalName)
|
||||
require.Contains(t, stored.RelativePath, "projects/12/")
|
||||
require.FileExists(t, stored.AbsolutePath)
|
||||
}
|
||||
|
||||
func TestSaveNeutralizesPathTraversal(t *testing.T) {
|
||||
service := NewService(t.TempDir())
|
||||
|
||||
stored, err := service.Save(12, "..\\..\\secret.txt", strings.NewReader("hello"))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "secret.txt", stored.OriginalName)
|
||||
require.Contains(t, stored.RelativePath, "projects/12/")
|
||||
}
|
||||
Reference in New Issue
Block a user