This commit is contained in:
Martino Ferrari
2026-04-26 11:01:55 +02:00
parent 91b42027c9
commit e83e183673
17 changed files with 1009 additions and 182 deletions
+28
View File
@@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
"time"
"unicode"
)
// ErrNotFound is returned when the requested interface does not exist.
@@ -35,6 +36,21 @@ func New(storageDir string) (*Store, error) {
return &Store{dir: dir}, nil
}
// validateID returns an error if id could be used for path traversal or is
// otherwise unsafe. Valid IDs contain only letters, digits, hyphens, and
// underscores.
func validateID(id string) error {
if id == "" {
return fmt.Errorf("interface ID must not be empty")
}
for _, r := range id {
if !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '-' && r != '_' {
return fmt.Errorf("invalid character %q in interface ID", r)
}
}
return nil
}
func (s *Store) filePath(id string) string {
return filepath.Join(s.dir, id+".xml")
}
@@ -85,6 +101,9 @@ func (s *Store) readMeta(id string) (InterfaceMeta, error) {
// Get returns the raw XML bytes for the interface with the given ID.
func (s *Store) Get(id string) ([]byte, error) {
if err := validateID(id); err != nil {
return nil, fmt.Errorf("%w: %v", ErrNotFound, err)
}
data, err := os.ReadFile(s.filePath(id))
if errors.Is(err, os.ErrNotExist) {
return nil, ErrNotFound
@@ -114,6 +133,9 @@ func (s *Store) Create(xmlData []byte) (string, error) {
// Update replaces the XML for an existing interface.
func (s *Store) Update(id string, xmlData []byte) error {
if err := validateID(id); err != nil {
return ErrNotFound
}
if _, err := os.Stat(s.filePath(id)); errors.Is(err, os.ErrNotExist) {
return ErrNotFound
}
@@ -122,6 +144,9 @@ func (s *Store) Update(id string, xmlData []byte) error {
// Delete removes the interface with the given ID.
func (s *Store) Delete(id string) error {
if err := validateID(id); err != nil {
return ErrNotFound
}
err := os.Remove(s.filePath(id))
if errors.Is(err, os.ErrNotExist) {
return ErrNotFound
@@ -131,6 +156,9 @@ func (s *Store) Delete(id string) error {
// Clone duplicates an interface, assigning a new unique ID.
func (s *Store) Clone(srcID string) (string, error) {
if err := validateID(srcID); err != nil {
return "", ErrNotFound
}
data, err := s.Get(srcID)
if err != nil {
return "", err