diff --git a/cmd/dkl-dir2config/render-context.go b/cmd/dkl-dir2config/render-context.go
index 5ea2a72..b6e18cc 100644
--- a/cmd/dkl-dir2config/render-context.go
+++ b/cmd/dkl-dir2config/render-context.go
@@ -8,6 +8,7 @@ import (
"math/rand"
"path"
"reflect"
+ "strconv"
"strings"
"github.com/cespare/xxhash"
@@ -290,6 +291,14 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]any {
"host_download_token": func() (s string) {
return "{{ host_download_token }}"
},
+ "asset_download_token": func(args ...string) (s string) {
+ argsStr := new(strings.Builder)
+ for _, arg := range args {
+ argsStr.WriteByte(' ')
+ argsStr.WriteString(strconv.Quote(arg))
+ }
+ return "{{ asset_download_token" + argsStr.String() + " }}"
+ },
"hosts_of_group": func() (hosts []any) {
hosts = make([]any, 0)
diff --git a/cmd/dkl-local-server/html.go b/cmd/dkl-local-server/html.go
new file mode 100644
index 0000000..d0d20fe
--- /dev/null
+++ b/cmd/dkl-local-server/html.go
@@ -0,0 +1,15 @@
+package main
+
+func htmlHeader(title string) string {
+ return `
+
+
+ ` + title + `
+
+
+` + title + `
+`
+}
+
+var htmlFooter = `
+`
diff --git a/cmd/dkl-local-server/render-context.go b/cmd/dkl-local-server/render-context.go
index b70a7c0..8f57fe7 100644
--- a/cmd/dkl-local-server/render-context.go
+++ b/cmd/dkl-local-server/render-context.go
@@ -14,6 +14,7 @@ import (
"path"
"path/filepath"
"text/template"
+ "time"
cfsslconfig "github.com/cloudflare/cfssl/config"
restful "github.com/emicklei/go-restful"
@@ -237,6 +238,32 @@ func (ctx *renderContext) TemplateFuncs() map[string]any {
}
}
+ return
+ },
+ "asset_download_token": func(asset string, params ...string) (token string, err error) {
+ now := time.Now()
+ exp := now.Add(24 * time.Hour) // expire in 24h by default
+ if len(params) != 0 {
+ exp, err = parseCertDuration(params[0], now)
+ if err != nil {
+ return
+ }
+ }
+
+ set := DownloadSet{
+ Expiry: exp,
+ Items: []DownloadSetItem{
+ {
+ Kind: "host",
+ Name: ctx.Host.Name,
+ Assets: []string{asset},
+ },
+ },
+ }
+
+ privKey, _ := dlsSigningKeys()
+ token = set.Signed(privKey)
+
return
},
} {
diff --git a/cmd/dkl-local-server/ws-download-set.go b/cmd/dkl-local-server/ws-download-set.go
index 71df998..1bf5734 100644
--- a/cmd/dkl-local-server/ws-download-set.go
+++ b/cmd/dkl-local-server/ws-download-set.go
@@ -75,6 +75,28 @@ func (s *DownloadSet) Decode(encoded string) (err error) {
return
}
+func (s DownloadSet) Signed(privKey ed25519.PrivateKey) string {
+ buf := new(bytes.Buffer)
+ {
+ setBytes := []byte(s.Encode())
+
+ w := lz4.NewWriter(buf)
+ w.Write(setBytes)
+ w.Close()
+ }
+
+ setBytes := buf.Bytes()
+ sig := ed25519.Sign(privKey, setBytes)
+
+ buf = bytes.NewBuffer(make([]byte, 0, 1+len(sig)+len(setBytes)))
+ buf.WriteByte(byte(len(sig)))
+ buf.Write(sig)
+ buf.Write(setBytes)
+
+ enc := base32.StdEncoding.WithPadding(base32.NoPadding)
+ return enc.EncodeToString(buf.Bytes())
+}
+
type DownloadSetItem struct {
Kind string
Name string
@@ -143,32 +165,8 @@ func wsSignDownloadSet(req *restful.Request, resp *restful.Response) {
Items: setReq.Items,
}
- buf := new(bytes.Buffer)
- {
- setBytes := []byte(set.Encode())
-
- w := lz4.NewWriter(buf)
- w.Write(setBytes)
- w.Close()
- }
-
- setBytes := buf.Bytes()
-
- privkey, pubkey := dlsSigningKeys()
- sig := ed25519.Sign(privkey, setBytes)
-
- if !ed25519.Verify(pubkey, setBytes, sig) {
- wsError(resp, fmt.Errorf("signature self-check failed"))
- return
- }
-
- buf = bytes.NewBuffer(make([]byte, 0, 1+len(sig)+len(setBytes)))
- buf.WriteByte(byte(len(sig)))
- buf.Write(sig)
- buf.Write(setBytes)
-
- enc := base32.StdEncoding.WithPadding(base32.NoPadding)
- resp.WriteEntity(enc.EncodeToString(buf.Bytes()))
+ privKey, _ := dlsSigningKeys()
+ resp.WriteEntity(set.Signed(privKey))
}
func getDlSet(req *restful.Request) (*DownloadSet, *httperr.Error) {
@@ -248,28 +246,13 @@ func wsDownloadSet(req *restful.Request, resp *restful.Response) {
set, err := getDlSet(req)
if err != nil {
resp.WriteHeader(err.Status)
- resp.Write([]byte(`
-
-
- ` + err.Error() + `
-
-
-
-` + err.Error() + `
-`))
+ resp.Write([]byte(htmlHeader(err.Error())))
+ resp.Write([]byte(htmlFooter))
return
}
buf := new(bytes.Buffer)
- buf.WriteString(`
-
-
- Download set
-
-
-
-Download set
-`)
+ buf.WriteString(htmlHeader("Download set"))
cfg, err2 := readConfig()
if err2 != nil {
@@ -304,6 +287,6 @@ func wsDownloadSet(req *restful.Request, resp *restful.Response) {
}
}
- buf.WriteString("")
+ buf.WriteString(htmlFooter)
buf.WriteTo(resp)
}
diff --git a/cmd/dkl-local-server/ws-downloads.go b/cmd/dkl-local-server/ws-downloads.go
index 8cf26f7..54b8991 100644
--- a/cmd/dkl-local-server/ws-downloads.go
+++ b/cmd/dkl-local-server/ws-downloads.go
@@ -180,34 +180,20 @@ func wsDownloadPage(req *restful.Request, resp *restful.Response) {
spec, ok := wState.Get().Downloads[token]
if !ok {
resp.WriteHeader(http.StatusNotFound)
- resp.Write([]byte(`
-
-
- Token not found
-
-
-
-Token not found
-`))
+ resp.Write([]byte(htmlHeader("Token not found")))
+ resp.Write([]byte(htmlFooter))
return
}
buf := new(bytes.Buffer)
- fmt.Fprintf(buf, `
-
-
- Token assets: %s %s
-
-
-
-Token assets: %s %s
-
-`, spec.Kind, spec.Name, spec.Kind, spec.Name)
+ buf.WriteString(htmlHeader(fmt.Sprintf("Token assets: %s %s", spec.Kind, spec.Name)))
+ buf.WriteString("")
for _, asset := range spec.Assets {
fmt.Fprintf(buf, "- %s
\n", asset, asset)
}
+ buf.WriteString("
")
- buf.WriteString("
")
+ buf.WriteString(htmlFooter)
buf.WriteTo(resp)
}