84 lines
1.7 KiB
Go
84 lines
1.7 KiB
Go
|
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.
|
||
|
func NewFSStore(dirPath string) (Store, error) {
|
||
|
err := os.Mkdir(dirPath, 0700)
|
||
|
if err != nil && !errors.Is(err, fs.ErrExist) {
|
||
|
return nil, fmt.Errorf("making directory: %w", err)
|
||
|
}
|
||
|
return &fsStore{dirPath}, nil
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|