diff --git a/go.mod b/go.mod index e430c4e..62742e9 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/gorilla/mux v1.8.0 // indirect + github.com/matoous/go-nanoid/v2 v2.0.0 // indirect github.com/mediocregopher/radix/v4 v4.0.0-beta.1 // indirect github.com/minio/minio-go/v7 v7.0.10 // indirect ) diff --git a/go.sum b/go.sum index 32ea56e..250fdd2 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matoous/go-nanoid v1.5.0 h1:VRorl6uCngneC4oUQqOYtO3S0H5QKFtKuKycFG3euek= +github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= +github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0= +github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g= github.com/mediocregopher/radix/v4 v4.0.0-beta.1 h1:RDgQ4wCQ6f+pUsX20CIzjNJnI5P9KDw4j1sjOVHxo7Y= github.com/mediocregopher/radix/v4 v4.0.0-beta.1/go.mod h1:Z74pilm773ghbGV4EEoPvi6XWgkAfr0VCNkfa8gI1PU= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= @@ -39,6 +43,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tilinna/clock v1.0.2 h1:6BO2tyAC9JbPExKH/z9zl44FLu1lImh3nDNKA0kgrkI= github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -64,3 +69,4 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers.go b/handlers.go index d32c326..2ef5e47 100644 --- a/handlers.go +++ b/handlers.go @@ -3,13 +3,16 @@ package main import ( "encoding/json" "errors" + "fmt" "html/template" "io" "net/http" "os" + "strconv" "time" "github.com/gorilla/mux" + gonanoid "github.com/matoous/go-nanoid/v2" ) var globalStore store @@ -47,6 +50,8 @@ func executeTemplate(w io.Writer, name string, data interface{}) error { /* credentials */ +var idAlphabet = "0123456789abcdefghijklmnopqrstuvwxyz" + func getCredential(id string) (credential, error) { cred := credential{} @@ -100,3 +105,45 @@ func handleUpload(w http.ResponseWriter, req *http.Request) { func handleCreate(w http.ResponseWriter, req *http.Request) { executeTemplate(w, "create.tmpl", nil) } + +/* create form */ + +type createReq struct { + credential + Expires time.Duration +} + +func handleCreateForm(w http.ResponseWriter, req *http.Request) { + cred := credential{ + Endpoint: req.PostFormValue("Endpoint"), + Region: req.PostFormValue("Region"), + AccessKey: req.PostFormValue("AccessKey"), + SecretKey: req.PostFormValue("SecretKey"), + Prefix: req.PostFormValue("Prefix"), + } + if err := cred.validate(); err != nil { + errorResponse(w, req, fmt.Errorf("%w: %s", errBadRequest, err)) + return + } + + expiresN, err := strconv.ParseUint(req.PostFormValue("Expires"), 10, 64) + if err != nil { + errorResponse(w, req, fmt.Errorf("%w: %s", errBadRequest, err)) + return + } + expires := time.Duration(expiresN) + if expires < 10*time.Minute || expires > 90*24*time.Hour { + errorResponse(w, req, fmt.Errorf("%w: time must be between 10 minutes and 90 days", errBadRequest)) + return + } + + id := gonanoid.MustGenerate(idAlphabet, 20) + + err = setCredential(id, cred, expires) + if err != nil { + errorResponse(w, req, err) + return + } + + w.Write([]byte(id)) +} diff --git a/main.go b/main.go index b941251..05a09e5 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ func main() { router.Methods(http.MethodGet).PathPrefix("/assets").HandlerFunc(handleAssets) router.Methods(http.MethodGet).Path("/create").HandlerFunc(handleCreate) + router.Methods(http.MethodPost).Path("/create").HandlerFunc(handleCreateForm) uploadRouter := router.PathPrefix("/{id}").Subrouter() uploadTemplateRouter := uploadRouter.Path("").Subrouter() diff --git a/store.go b/store.go index b9b8a0f..ee16d36 100644 --- a/store.go +++ b/store.go @@ -82,7 +82,7 @@ func (s *redisStore) put(key string, data []byte, expire time.Duration) error { } expireS := int64(expire / time.Second) - err = s.client.Do(ctx, radix.FlatCmd(nil, "SETEX", key, expireS, data)) + err = s.client.Do(ctx, radix.FlatCmd(nil, "SETEX", "upl:"+key, expireS, data)) if err != nil { return err } diff --git a/web/create.tmpl b/web/create.tmpl index adfaa9c..270a1cb 100644 --- a/web/create.tmpl +++ b/web/create.tmpl @@ -1,5 +1,7 @@ -{{template "head.tmpl" "Create Dropbox"}} -
+{{template "head.tmpl" "Create dropbox"}} + + +

Create a dropbox

@@ -32,7 +34,7 @@ type="text" id="options-region" name="Region" - placeholder="us-west-2"> + placeholder="us-east-1">
@@ -67,7 +69,7 @@ class="rounded" type="checkbox" id="options-save-upload" - data-save="Prefix,ExpiryNumber,ExpiryUnits"> + data-save="Prefix,ExpiresNumber,ExpiresUnits">
@@ -83,24 +85,24 @@ value="{random}/">

- Files will be uploaded with this prefix. For a random 16-character [a-z0-9] prefix , use {random}. + Files will be uploaded with this prefix. For a random [a-z0-9]{16} prefix , use {random}.

- +
+
+
+ +
+
+
{{template "foot.tmpl"}} diff --git a/web/src/log.js b/web/src/log.js index 8230e7a..f7aea52 100644 --- a/web/src/log.js +++ b/web/src/log.js @@ -1,9 +1,9 @@ import filesize from 'filesize'; class Log { - constructor(selector, key) { + constructor(target, key) { this.key = key; - this.target = document.querySelector(selector); + this.target = target; this.items = []; this.localStorageLoad(); @@ -21,12 +21,16 @@ class Log { static renderItem(item) { const base = document.createElement('div'); - base.classList.add('log-item'); + base.classList.add('mt-1'); + base.classList.add('flex'); const url = document.createElement('input'); + url.type = 'url'; url.value = item.location; url.setAttribute('readonly', ''); - url.classList.add('log-url'); + url.classList.add('w-full'); + url.classList.add('rounded-l-md'); + url.classList.add('border-gray-400'); url.addEventListener('click', (e) => { e.target.setSelectionRange(0, e.target.value.length); }); @@ -34,7 +38,17 @@ class Log { const size = document.createElement('span'); size.innerText = filesize(item.size); - size.classList.add('log-size'); + size.classList.add('text-sm'); + size.classList.add('whitespace-nowrap'); + size.classList.add('px-2'); + size.classList.add('bg-gray-50'); + size.classList.add('text-gray-500'); + size.classList.add('rounded-r-md'); + size.classList.add('border'); + size.classList.add('border-gray-400'); + size.classList.add('border-l-0'); + size.classList.add('inline-flex'); + size.classList.add('items-center'); base.appendChild(size); return base; diff --git a/web/upload-not-found.tmpl b/web/upload-not-found.tmpl index 7e163ac..4f46dd6 100644 --- a/web/upload-not-found.tmpl +++ b/web/upload-not-found.tmpl @@ -1,8 +1,10 @@ -{{template "head.tmpl" "Dropbox Not Found"}} -
-
-

Dropbox Not Found

-

The dropbox you are looking for doesn't exist or has expired.

-
+{{template "head.tmpl" "Dropbox not found"}} +
+

Dropbox not found

+
+

+ The dropbox you are looking for doesn't exist or has expired. +

+
{{template "foot.tmpl"}} diff --git a/web/upload.tmpl b/web/upload.tmpl index db5710a..2ccfa03 100644 --- a/web/upload.tmpl +++ b/web/upload.tmpl @@ -1,13 +1,18 @@ -{{template "head.tmpl" "Dropbox Not Found"}} -
-
-
-
-
-

Completed

- -
-
+{{template "head.tmpl" "Dropbox"}} +
+
+
+
+
+

Completed

+ + + +
+
{{template "foot.tmpl"}}