secrets migration & restitution
This commit is contained in:
@ -8,9 +8,13 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"m.cluseau.fr/go/httperr"
|
||||
|
||||
"novit.tech/direktil/local-server/secretstore"
|
||||
)
|
||||
|
||||
@ -126,6 +130,7 @@ func unlockSecretStore(passphrase []byte) *httperr.Error {
|
||||
})
|
||||
|
||||
go updateState()
|
||||
go migrateSecrets()
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -147,7 +152,13 @@ func readSecret(name string, value any) (err error) {
|
||||
}
|
||||
|
||||
func writeSecret(name string, value any) (err error) {
|
||||
f, err := os.Create(secStorePath(name + ".data.new"))
|
||||
path := secStorePath(name + ".data.new")
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -167,5 +178,148 @@ func writeSecret(name string, value any) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
return os.Rename(f.Name(), secStorePath(name+".data"))
|
||||
err = os.Rename(f.Name(), secStorePath(name+".data"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go updateState()
|
||||
return
|
||||
}
|
||||
|
||||
var secL sync.Mutex
|
||||
|
||||
func updateSecret[T any](name string, update func(*T)) (err error) {
|
||||
secL.Lock()
|
||||
defer secL.Unlock()
|
||||
|
||||
v := new(T)
|
||||
err = readSecret(name, v)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
|
||||
update(v)
|
||||
|
||||
return writeSecret(name, *v)
|
||||
}
|
||||
|
||||
func updateSecretWithKey[T any](name, key string, update func(v *T)) (err error) {
|
||||
secL.Lock()
|
||||
defer secL.Unlock()
|
||||
|
||||
kvs := map[string]*T{}
|
||||
|
||||
err = readSecret(name, &kvs)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
|
||||
update(kvs[key])
|
||||
|
||||
return writeSecret(name, kvs)
|
||||
}
|
||||
|
||||
type KVSecrets[T any] struct{ Name string }
|
||||
|
||||
func (s KVSecrets[T]) Data() (kvs map[string]T, err error) {
|
||||
kvs = make(map[string]T)
|
||||
err = readSecret(s.Name, &kvs)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) Keys(prefix string) (keys []string, err error) {
|
||||
kvs, err := s.Data()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keys = make([]string, 0, len(kvs))
|
||||
|
||||
for k := range kvs {
|
||||
if !strings.HasPrefix(k, prefix) {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, k[len(prefix):])
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) Get(key string) (v T, found bool, err error) {
|
||||
kvs, err := s.Data()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
v, found = kvs[key]
|
||||
return
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) Put(key string, v T) (err error) {
|
||||
secL.Lock()
|
||||
defer secL.Unlock()
|
||||
|
||||
kvs, err := s.Data()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
kvs[key] = v
|
||||
err = writeSecret(s.Name, kvs)
|
||||
return
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) WsList(resp *restful.Response, prefix string) {
|
||||
keys, err := s.Keys(prefix)
|
||||
if err != nil {
|
||||
httperr.New(http.StatusInternalServerError, err).WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(keys)
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) WsGet(resp *restful.Response, key string) {
|
||||
keys, found, err := s.Get(key)
|
||||
if err != nil {
|
||||
httperr.New(http.StatusInternalServerError, err).WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
|
||||
if !found {
|
||||
ErrNotFound.WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(keys)
|
||||
}
|
||||
|
||||
func (s KVSecrets[T]) WsPut(req *restful.Request, resp *restful.Response, key string) {
|
||||
v := new(T)
|
||||
err := req.ReadEntity(v)
|
||||
if err != nil {
|
||||
httperr.New(http.StatusBadRequest, err).WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.Put(key, *v)
|
||||
if err != nil {
|
||||
httperr.New(http.StatusInternalServerError, err).WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user