download token: make a token page
- token page helps communicating a single link to multiple assets - provide an extra layer in case of "miss click" - ui: just link the page, not every asset of each download token.
This commit is contained in:
@ -1,8 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -149,3 +151,45 @@ func wsDownload(req *restful.Request, resp *restful.Response) {
|
|||||||
wsNotFound(resp)
|
wsNotFound(resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wsDownloadPage(req *restful.Request, resp *restful.Response) {
|
||||||
|
token := req.PathParameter("token")
|
||||||
|
|
||||||
|
spec, ok := wState.Get().Downloads[token]
|
||||||
|
if !ok {
|
||||||
|
resp.WriteHeader(http.StatusNotFound)
|
||||||
|
resp.Write([]byte(`<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Token not found</title>
|
||||||
|
<style>
|
||||||
|
@import url('/ui/style.css');
|
||||||
|
@import url('/ui/app.css');
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body><h1>Token not found</h1></body>
|
||||||
|
</html>`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
fmt.Fprintf(buf, `<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Token assets: %s %s</title>
|
||||||
|
<style>
|
||||||
|
@import url('/ui/style.css');
|
||||||
|
@import url('/ui/app.css');
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body><h1>Token assets: %s %s</h1>
|
||||||
|
<ul>
|
||||||
|
`, spec.Kind, spec.Name, spec.Kind, spec.Name)
|
||||||
|
|
||||||
|
for _, asset := range spec.Assets {
|
||||||
|
fmt.Fprintf(buf, "<li><a href=\"%s\" download>%s</a></li>\n", asset, asset)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("</ul></body></html>")
|
||||||
|
buf.WriteTo(resp)
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ func registerWS(rest *restful.Container) {
|
|||||||
Route(ws.POST("/store.tar").To(wsStoreUpload).
|
Route(ws.POST("/store.tar").To(wsStoreUpload).
|
||||||
Consumes(mime.TAR).
|
Consumes(mime.TAR).
|
||||||
Doc("Upload an existing store")).
|
Doc("Upload an existing store")).
|
||||||
|
Route(ws.GET("/downloads/{token}/").To(wsDownloadPage)).
|
||||||
Route(ws.GET("/downloads/{token}/{asset}").To(wsDownload).
|
Route(ws.GET("/downloads/{token}/{asset}").To(wsDownload).
|
||||||
Param(ws.PathParameter("token", "the download token")).
|
Param(ws.PathParameter("token", "the download token")).
|
||||||
Param(ws.PathParameter("asset", "the requested asset")).
|
Param(ws.PathParameter("asset", "the requested asset")).
|
||||||
|
@ -27,16 +27,15 @@ export default {
|
|||||||
}[this.kind]
|
}[this.kind]
|
||||||
},
|
},
|
||||||
downloads() {
|
downloads() {
|
||||||
let ret = []
|
return Object.entries(this.state.Downloads)
|
||||||
Object.entries(this.state.Downloads)
|
|
||||||
.filter(e => { let d=e[1]; return d.Kind == this.kind && d.Name == this.name })
|
.filter(e => { let d=e[1]; return d.Kind == this.kind && d.Name == this.name })
|
||||||
.forEach(e => {
|
.map(e => {
|
||||||
let token= e[0], d = e[1]
|
const token= e[0];
|
||||||
d.Assets.forEach(asset => {
|
return {
|
||||||
ret.push({name: asset, url: '/public/downloads/'+token+'/'+asset})
|
text: token.substring(0, 5) + '...',
|
||||||
|
url: '/public/downloads/'+token+"/",
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
|
||||||
return ret
|
|
||||||
},
|
},
|
||||||
assets() {
|
assets() {
|
||||||
return this.availableAssets.filter(a => this.selectedAssets[a])
|
return this.availableAssets.filter(a => this.selectedAssets[a])
|
||||||
@ -64,9 +63,9 @@ export default {
|
|||||||
{{" "}}
|
{{" "}}
|
||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
<p><button :disabled="createDisabled || assets.length==0" @click="createToken">Create links</button></p>
|
<p><button :disabled="createDisabled || assets.length==0" @click="createToken">Create link</button></p>
|
||||||
<template v-if="downloads.length">
|
<template v-if="downloads.length">
|
||||||
<h4>Active links</h4>
|
<h4>Active links</h4>
|
||||||
<p class="download-links"><template v-for="d in downloads"><a :href="d.url" download>{{ d.name }}</a>{{" "}}</template></p>
|
<p class="download-links"><template v-for="d in downloads"><a :href="d.url" target="_blank">{{ d.text }}</a>{{" "}}</template></p>
|
||||||
</template>`
|
</template>`
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user