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