40d08139db
This allows the user to call it even after the store has been unlock in order to get the admin token.
196 lines
3.0 KiB
Go
196 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"io"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
restful "github.com/emicklei/go-restful"
|
|
"m.cluseau.fr/go/httperr"
|
|
"novit.tech/direktil/local-server/secretstore"
|
|
)
|
|
|
|
type NamedPassphrase struct {
|
|
Name string
|
|
Passphrase []byte
|
|
}
|
|
|
|
func wsUnlockStore(req *restful.Request, resp *restful.Response) {
|
|
np := NamedPassphrase{}
|
|
err := req.ReadEntity(&np)
|
|
if err != nil {
|
|
resp.WriteError(http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
defer secretstore.Memzero(np.Passphrase)
|
|
|
|
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 secStore.Unlocked() {
|
|
if secStore.HasKey(np.Passphrase) {
|
|
resp.WriteEntity(adminToken)
|
|
} else {
|
|
wsError(resp, ErrUnauthorized)
|
|
}
|
|
return
|
|
}
|
|
|
|
if err := unlockSecretStore(np.Name, np.Passphrase); err.Any() {
|
|
err.WriteJSON(resp.ResponseWriter)
|
|
return
|
|
}
|
|
|
|
resp.WriteEntity(adminToken)
|
|
}
|
|
|
|
func wsStoreDownload(req *restful.Request, resp *restful.Response) {
|
|
token := req.QueryParameter("token")
|
|
if token != wState.Get().Store.DownloadToken {
|
|
wsError(resp, ErrInvalidToken)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
arch := tar.NewWriter(buf)
|
|
|
|
root := os.DirFS(secStoreRoot())
|
|
|
|
err := fs.WalkDir(root, ".", func(path string, d fs.DirEntry, readErr error) (err error) {
|
|
if readErr != nil {
|
|
err = readErr
|
|
return
|
|
}
|
|
|
|
if path == "." {
|
|
return
|
|
}
|
|
|
|
fi, err := d.Info()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
hdr, err := tar.FileInfoHeader(fi, "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
hdr.Name = path
|
|
hdr.Uid = 0
|
|
hdr.Gid = 0
|
|
|
|
err = arch.WriteHeader(hdr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if fi.IsDir() {
|
|
return
|
|
}
|
|
|
|
f, err := root.Open(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer f.Close()
|
|
|
|
io.Copy(arch, f)
|
|
|
|
return
|
|
})
|
|
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
err = arch.Close()
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
buf.WriteTo(resp)
|
|
}
|
|
|
|
func wsStoreUpload(req *restful.Request, resp *restful.Response) {
|
|
if !secStore.IsNew() {
|
|
wsError(resp, httperr.BadRequest("store is not new"))
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
_, err := io.Copy(buf, req.Request.Body)
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
arch := tar.NewReader(buf)
|
|
|
|
root := secStoreRoot()
|
|
|
|
for {
|
|
hdr, err := arch.Next()
|
|
if err == io.EOF {
|
|
err = nil
|
|
break
|
|
} else if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
log.Print(hdr.Name)
|
|
|
|
fullPath := filepath.Join(root, hdr.Name)
|
|
|
|
switch {
|
|
case hdr.FileInfo().IsDir():
|
|
err = os.MkdirAll(fullPath, 0700)
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
default:
|
|
content, err := io.ReadAll(io.LimitReader(arch, hdr.Size))
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
err = os.WriteFile(fullPath, content, 0600)
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
wsError(resp, err)
|
|
return
|
|
}
|
|
|
|
openSecretStore()
|
|
|
|
resp.WriteEntity(map[string]any{"ok": true})
|
|
}
|