named passphrases (+deletion by name)
This commit is contained in:
@ -26,7 +26,7 @@ func authorizeToken(r *http.Request, token string) bool {
|
||||
}
|
||||
|
||||
func forbidden(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("denied access to %s from %s", r.RequestURI, r.RemoteAddr)
|
||||
log.Printf("denied access to %s from %s", r.URL.Path, r.RemoteAddr)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,12 @@ func main() {
|
||||
}
|
||||
if autoUnlock != "" {
|
||||
log.Printf("auto-unlocking the store")
|
||||
err := unlockSecretStore([]byte(autoUnlock))
|
||||
err := unlockSecretStore("test", []byte(autoUnlock))
|
||||
if err.Any() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("store auto-unlocked, admin token is ", adminToken)
|
||||
log.Print("store auto-unlocked, token is ", adminToken)
|
||||
}
|
||||
|
||||
os.Setenv("DLS_AUTO_UNLOCK", "")
|
||||
|
@ -63,7 +63,7 @@ var (
|
||||
ErrInvalidPassphrase = httperr.NewStd(2, http.StatusBadRequest, "invalid passphrase")
|
||||
)
|
||||
|
||||
func unlockSecretStore(passphrase []byte) (err httperr.Error) {
|
||||
func unlockSecretStore(name string, passphrase []byte) (err httperr.Error) {
|
||||
unlockMutex.Lock()
|
||||
defer unlockMutex.Unlock()
|
||||
|
||||
@ -72,7 +72,7 @@ func unlockSecretStore(passphrase []byte) (err httperr.Error) {
|
||||
}
|
||||
|
||||
if secStore.IsNew() {
|
||||
err := secStore.Init(passphrase)
|
||||
err := secStore.Init(name, passphrase)
|
||||
if err != nil {
|
||||
return httperr.Internal(err)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ type State struct {
|
||||
|
||||
Store struct {
|
||||
DownloadToken string
|
||||
KeyNames []string
|
||||
}
|
||||
|
||||
Clusters []ClusterState
|
||||
@ -59,14 +60,21 @@ func init() {
|
||||
func updateState() {
|
||||
log.Print("updating state")
|
||||
|
||||
// store key names
|
||||
keyNames := make([]string, 0, len(secStore.Keys))
|
||||
for _, key := range secStore.Keys {
|
||||
keyNames = append(keyNames, key.Name)
|
||||
}
|
||||
|
||||
// config
|
||||
cfg, err := readConfig()
|
||||
if err != nil {
|
||||
wState.Change(func(v *State) { v.HasConfig = false; v.Config = nil })
|
||||
wState.Change(func(v *State) { v.HasConfig = false; v.Config = nil; v.Store.KeyNames = keyNames })
|
||||
return
|
||||
}
|
||||
|
||||
if secStore.IsNew() || !secStore.Unlocked() {
|
||||
wState.Change(func(v *State) { v.HasConfig = false; v.Config = nil })
|
||||
wState.Change(func(v *State) { v.HasConfig = false; v.Config = nil; v.Store.KeyNames = keyNames })
|
||||
return
|
||||
}
|
||||
|
||||
@ -122,7 +130,7 @@ func updateState() {
|
||||
// done
|
||||
wState.Change(func(v *State) {
|
||||
v.HasConfig = true
|
||||
//v.Config = cfg
|
||||
v.Store.KeyNames = keyNames
|
||||
v.Clusters = clusters
|
||||
v.Hosts = hosts
|
||||
})
|
||||
|
@ -14,15 +14,32 @@ import (
|
||||
"m.cluseau.fr/go/httperr"
|
||||
)
|
||||
|
||||
type NamedPassphrase struct {
|
||||
Name string
|
||||
Passphrase []byte
|
||||
}
|
||||
|
||||
func wsUnlockStore(req *restful.Request, resp *restful.Response) {
|
||||
var passphrase string
|
||||
err := req.ReadEntity(&passphrase)
|
||||
np := NamedPassphrase{}
|
||||
err := req.ReadEntity(&np)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := unlockSecretStore([]byte(passphrase)); err.Any() {
|
||||
if secStore.IsNew() {
|
||||
if len(np.Name) == 0 {
|
||||
wsBadRequest(resp, "no name given")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(np.Passphrase) == 0 {
|
||||
wsBadRequest(resp, "no passphrase given")
|
||||
return
|
||||
}
|
||||
|
||||
if err := unlockSecretStore(np.Name, np.Passphrase); err.Any() {
|
||||
err.WriteJSON(resp.ResponseWriter)
|
||||
return
|
||||
}
|
||||
|
@ -1,24 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"novit.tech/direktil/local-server/secretstore"
|
||||
)
|
||||
|
||||
func wsStoreAddKey(req *restful.Request, resp *restful.Response) {
|
||||
var passphrase string
|
||||
np := NamedPassphrase{}
|
||||
|
||||
err := req.ReadEntity(&passphrase)
|
||||
err := req.ReadEntity(&np)
|
||||
if err != nil {
|
||||
wsBadRequest(resp, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(passphrase) == 0 {
|
||||
np.Name = strings.TrimSpace(np.Name)
|
||||
|
||||
if len(np.Name) == 0 {
|
||||
wsBadRequest(resp, "no name given")
|
||||
return
|
||||
}
|
||||
|
||||
if len(np.Passphrase) == 0 {
|
||||
wsBadRequest(resp, "no passphrase given")
|
||||
return
|
||||
}
|
||||
|
||||
secStore.AddKey([]byte(passphrase))
|
||||
secStore.AddKey(np.Name, np.Passphrase)
|
||||
defer updateState()
|
||||
|
||||
for _, k := range secStore.Keys {
|
||||
if k.Name == np.Name {
|
||||
wsBadRequest(resp, "there's already a passphrase named "+strconv.Quote(np.Name))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = secStore.SaveTo(secKeysStorePath())
|
||||
if err != nil {
|
||||
wsError(resp, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func wsStoreDelKey(req *restful.Request, resp *restful.Response) {
|
||||
name := ""
|
||||
|
||||
err := req.ReadEntity(&name)
|
||||
if err != nil {
|
||||
wsBadRequest(resp, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
newKeys := make([]secretstore.KeyEntry, 0, len(secStore.Keys))
|
||||
for _, k := range secStore.Keys {
|
||||
if k.Name == name {
|
||||
continue
|
||||
}
|
||||
|
||||
newKeys = append(newKeys, k)
|
||||
}
|
||||
|
||||
if len(newKeys) == 0 {
|
||||
wsBadRequest(resp, "can't remove the last key from the store")
|
||||
return
|
||||
}
|
||||
|
||||
secStore.Keys = newKeys
|
||||
defer updateState()
|
||||
|
||||
err = secStore.SaveTo(secKeysStorePath())
|
||||
if err != nil {
|
||||
wsError(resp, err)
|
||||
|
@ -27,7 +27,7 @@ func registerWS(rest *restful.Container) {
|
||||
Produces(mime.JSON).
|
||||
Consumes(mime.JSON).
|
||||
Route(ws.POST("/unlock-store").To(wsUnlockStore).
|
||||
Reads("").
|
||||
Reads(NamedPassphrase{}).
|
||||
Writes("").
|
||||
Doc("Try to unlock the store")).
|
||||
Route(ws.GET("/store.tar").To(wsStoreDownload).
|
||||
@ -54,8 +54,11 @@ func registerWS(rest *restful.Container) {
|
||||
|
||||
// - store management
|
||||
ws.Route(ws.POST("/store/add-key").To(wsStoreAddKey).
|
||||
Consumes(mime.JSON).Reads("").
|
||||
Consumes(mime.JSON).Reads(NamedPassphrase{}).
|
||||
Doc("Add an unlock key to the store"))
|
||||
ws.Route(ws.POST("/store/delete-key").To(wsStoreDelKey).
|
||||
Consumes(mime.JSON).Reads("").
|
||||
Doc("Remove an unlock key to the store (by its name)"))
|
||||
|
||||
// - downloads
|
||||
ws.Route(ws.POST("/authorize-download").To(wsAuthorizeDownload).
|
||||
|
Reference in New Issue
Block a user