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}) }