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() + ` -