59 lines
1.6 KiB
Go
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
|
|
}
|