2024-07-13 12:34:06 +00:00
|
|
|
package secrets
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
)
|
|
|
|
|
|
|
|
type fsStore struct {
|
|
|
|
dirPath string
|
|
|
|
}
|
|
|
|
|
|
|
|
type fsStorePayload[Body any] struct {
|
|
|
|
Version int
|
|
|
|
Body Body
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFSStore returns a Store which will store secrets to the given directory.
|
2024-09-09 14:34:00 +00:00
|
|
|
// The directory must already exist.
|
|
|
|
func NewFSStore(dirPath string) Store {
|
|
|
|
return &fsStore{dirPath}
|
2024-07-13 12:34:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *fsStore) path(id ID) string {
|
|
|
|
return filepath.Join(s.dirPath, string(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *fsStore) Set(_ context.Context, id ID, payload any) error {
|
|
|
|
path := s.path(id)
|
|
|
|
|
|
|
|
f, err := os.Create(path)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("creating file %q: %w", path, err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
if err := json.NewEncoder(f).Encode(fsStorePayload[any]{
|
|
|
|
Version: 1,
|
|
|
|
Body: payload,
|
|
|
|
}); err != nil {
|
|
|
|
return fmt.Errorf("writing JSON encoded payload to %q: %w", path, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *fsStore) Get(_ context.Context, into any, id ID) error {
|
|
|
|
path := s.path(id)
|
|
|
|
|
|
|
|
f, err := os.Open(path)
|
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
|
|
return ErrNotFound
|
|
|
|
} else if err != nil {
|
|
|
|
return fmt.Errorf("creating file %q: %w", path, err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
var fullPayload fsStorePayload[json.RawMessage]
|
|
|
|
if err := json.NewDecoder(f).Decode(&fullPayload); err != nil {
|
|
|
|
return fmt.Errorf("decoding JSON payload from %q: %w", path, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if fullPayload.Version != 1 {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"unexpected JSON payload version %d", fullPayload.Version,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(fullPayload.Body, into); err != nil {
|
|
|
|
return fmt.Errorf(
|
|
|
|
"decoding JSON payload body from %q into %T: %w", path, into, err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|