Files
template-vitrine/backend/internal/modules/customerverification/storage.go
T
Xor290 919c807004
ci-api / test (push) Failing after 8m7s
ci-web / test (push) Failing after 5m5s
chore: build
2026-09-20 12:18:33 +02:00

59 lines
1.6 KiB
Go

package customerverification
import (
"fmt"
"io"
"os"
"path/filepath"
)
// allowedTypes mirrors media.allowedTypes but is kept separate on purpose:
// verification documents are never routed through the public media module
// (whose storage backends always return a publicly reachable URL -- fine
// for product photos, never acceptable for an ID document). This is a
// small, private, local-disk-only store instead.
var allowedTypes = map[string]string{
"image/jpeg": ".jpg",
"image/png": ".png",
}
// Storage persists ID document images under a directory that main.go must
// never mount as a static file route. Files are only ever read back through
// Handler.serveDocument, which checks the caller is the admin or the
// document's own customer before streaming bytes.
type Storage struct {
dir string
}
func NewStorage(dir string) (*Storage, error) {
if err := os.MkdirAll(dir, 0o700); err != nil {
return nil, fmt.Errorf("create verification upload dir: %w", err)
}
return &Storage{dir: dir}, nil
}
func (s *Storage) Save(key string, reader io.Reader) error {
dest := filepath.Join(s.dir, filepath.Base(key))
f, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
if err != nil {
return fmt.Errorf("create file: %w", err)
}
defer f.Close()
if _, err := io.Copy(f, reader); err != nil {
return fmt.Errorf("write file: %w", err)
}
return nil
}
func (s *Storage) Path(key string) string {
return filepath.Join(s.dir, filepath.Base(key))
}
func (s *Storage) Delete(key string) error {
err := os.Remove(s.Path(key))
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("delete file: %w", err)
}
return nil
}