diff --git a/assets/templates/html/pasteMeta.html.tmpl b/assets/templates/html/pasteMeta.html.tmpl
index 15c113d..5c50084 100644
--- a/assets/templates/html/pasteMeta.html.tmpl
+++ b/assets/templates/html/pasteMeta.html.tmpl
@@ -6,8 +6,8 @@
{{.Host}}/{{.Paste.Key}}{{.FileExt}}
---
-{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
-with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}
+{{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
+with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}
{{else -}}
with delete token: <unknown>
{{end -}}
@@ -18,18 +18,11 @@ created: unknown
{{else -}}
created: {{.Paste.TimeCreated}}
{{end -}}
-delete token: {{.CanDelete.String}}
+delete token: {{.CanDelete}}
-{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
+{{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
```
-# To delete this {{.Paste.Type}}, execute:
-{{- /*
- We have the option here to take the deleteToken from the user request or
- from .Paste. Both are equivalent as long as .CanDelete is correct. We
- use the .Request value, because leaking the deleteToken would be a more
- dramatic vulnerability.
-*/}}
-curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}"
+curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"
```
{{end}}
diff --git a/assets/templates/txt/pasteMeta.txt.tmpl b/assets/templates/txt/pasteMeta.txt.tmpl
index 04cb8dc..c2c5ee5 100644
--- a/assets/templates/txt/pasteMeta.txt.tmpl
+++ b/assets/templates/txt/pasteMeta.txt.tmpl
@@ -1,6 +1,6 @@
{{.Host}}/{{.Paste.Key}}{{.FileExt}}
---
-{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
+{{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}
{{else -}}
with delete token:
@@ -11,17 +11,11 @@ created: unknown
{{else -}}
created: {{.Paste.TimeCreated}}
{{end -}}
-delete token: {{.CanDelete.String}}
+delete token: {{.CanDelete}}
-{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
+{{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
```
# To delete this {{.Paste.Type}}, execute:
-{{- /*
- We have the option here to take the deleteToken from the user request or
- from .Paste. Both are equivalent as long as .CanDelete is correct. We
- use the .Request value, because leaking the deleteToken would be a more
- dramatic vulnerability.
-*/ -}}
-curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}"
+curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"
```
{{end}}
diff --git a/handlers.go b/handlers.go
index c491f34..77d1ced 100644
--- a/handlers.go
+++ b/handlers.go
@@ -28,6 +28,31 @@ const (
const cookieDeleteToken = "owner_token"
+type canDelete uint
+
+const (
+ canDeleteUndef canDelete = iota
+ canDeleteYes
+ canDeleteNo
+)
+
+func (cd *canDelete) Bool() bool {
+ return *cd == canDeleteYes
+}
+
+func (cd *canDelete) String() string {
+ switch *cd {
+ case canDeleteUndef:
+ return "undefined"
+ case canDeleteYes:
+ return "correct"
+ case canDeleteNo:
+ return "invalid"
+ default:
+ panic("unreachable")
+ }
+}
+
func (rl *rushlink) staticGetHandler(w http.ResponseWriter, r *http.Request) {
rl.renderStatic(w, r, mux.Vars(r)["path"])
}
@@ -79,24 +104,22 @@ func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request)
}
func (rl *rushlink) viewPasteHandler(w http.ResponseWriter, r *http.Request) {
- rl.viewPasteHandlerInner(w, r, 0)
+ rl.viewPasteHandlerFlags(w, r, 0)
}
func (rl *rushlink) viewPasteHandlerNoRedirect(w http.ResponseWriter, r *http.Request) {
- rl.viewPasteHandlerInner(w, r, viewNoRedirect)
+ rl.viewPasteHandlerFlags(w, r, viewNoRedirect)
}
func (rl *rushlink) viewPasteHandlerMeta(w http.ResponseWriter, r *http.Request) {
- rl.viewPasteHandlerInner(w, r, viewShowMeta)
+ rl.viewPasteHandlerFlags(w, r, viewShowMeta)
}
-func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request, flags viewPaste) {
+func (rl *rushlink) viewPasteHandlerFlags(w http.ResponseWriter, r *http.Request, flags viewPaste) {
vars := mux.Vars(r)
key := vars["key"]
var p *db.Paste
- var fuID *uuid.UUID
var fu *db.FileUpload
- var fileExt string
if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
var err error
p, err = db.GetPaste(tx, key)
@@ -106,12 +129,10 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
if p != nil && p.Type == db.PasteTypeFileUpload {
var id uuid.UUID
copy(id[:], p.Content)
- fuID = &id
fu, err = db.GetFileUpload(tx, id)
if err != nil {
return err
}
- fileExt = fu.Ext()
}
return nil
}); err != nil {
@@ -123,30 +144,12 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
return
}
- if flags&viewShowMeta != 0 {
- canDelete := struct {
- Bool bool
- String string
- }{Bool: false}
- deleteToken := getDeleteTokenFromRequest(r)
- if deleteToken == "" {
- canDelete.String = "undefined"
- } else {
- if subtle.ConstantTimeCompare([]byte(deleteToken), []byte(p.DeleteToken)) == 1 {
- canDelete.Bool = true
- canDelete.String = "correct"
- } else {
- canDelete.String = "invalid"
- }
- }
+ rl.viewPasteHandlerInner(w, r, flags, p, fu)
+}
- data := map[string]interface{}{
- "Paste": p,
- "FileExt": fileExt,
- "CanDelete": canDelete,
- }
- rl.render(w, r, "pasteMeta", data)
- return
+func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request, flags viewPaste, p *db.Paste, fu *db.FileUpload) {
+ if flags&viewShowMeta != 0 {
+ rl.viewPasteHandlerInnerMeta(w, r, p, fu)
}
switch p.State {
@@ -155,7 +158,7 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
switch p.Type {
case db.PasteTypeFileUpload:
if fu == nil {
- panic(fmt.Sprintf("file for id %v does not exist in database\n", fuID))
+ panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
}
location = fu.URL().String()
break
@@ -176,6 +179,46 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
}
}
+func (rl *rushlink) viewPasteHandlerInnerMeta(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
+ var cd canDelete
+ deleteToken := getDeleteTokenFromRequest(r)
+ if deleteToken != "" {
+ if subtle.ConstantTimeCompare([]byte(deleteToken), []byte(p.DeleteToken)) == 1 {
+ cd = canDeleteYes
+ } else {
+ cd = canDeleteNo
+ }
+ }
+
+ var fileExt string
+ if fu != nil {
+ fileExt = fu.Ext()
+ }
+ data := map[string]interface{}{
+ "Paste": p,
+ "FileExt": fileExt,
+ "CanDelete": cd,
+ "CanDeleteBool": cd.Bool(),
+ }
+ rl.render(w, r, "pasteMeta", data)
+ return
+}
+
+func (rl *rushlink) viewCreateSuccess(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
+ var fileExt string
+ if fu != nil {
+ fileExt = fu.Ext()
+ }
+ data := map[string]interface{}{
+ "Paste": p,
+ "FileExt": fileExt,
+ "CanDelete": canDeleteYes,
+ "CanDeleteBool": true,
+ }
+ rl.render(w, r, "pasteMeta", data)
+ return
+}
+
func (rl *rushlink) newPasteHandler(w http.ResponseWriter, r *http.Request) {
file, fileHeader, err := r.FormFile("file")
if err == nil {
@@ -216,7 +259,7 @@ func (rl *rushlink) newFileUploadPasteHandler(w http.ResponseWriter, r *http.Req
}); err != nil {
panic(err)
}
- rl.renderCreateSuccess(w, r, paste, fu)
+ rl.viewCreateSuccess(w, r, paste, fu)
}
func (rl *rushlink) newPasteHandlerURLEncoded(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
@@ -256,7 +299,7 @@ func (rl *rushlink) newRedirectPasteHandler(w http.ResponseWriter, r *http.Reque
}); err != nil {
panic(err)
}
- rl.renderCreateSuccess(w, r, paste, nil)
+ rl.viewCreateSuccess(w, r, paste, nil)
}
// Delete a URL from the database
@@ -297,7 +340,7 @@ func (rl *rushlink) deletePasteHandler(w http.ResponseWriter, r *http.Request) {
rl.renderError(w, r, errorCode, fmt.Sprintf("error: %v\n", err))
return
}
- rl.renderCreateSuccess(w, r, paste, nil)
+ rl.viewCreateSuccess(w, r, paste, nil)
}
// Add a new fileUpload redirect to the database
diff --git a/views.go b/views.go
index 10d5f6a..88cdfee 100644
--- a/views.go
+++ b/views.go
@@ -9,7 +9,6 @@ import (
"io"
"log"
"net/http"
- "net/url"
"path/filepath"
"regexp"
"runtime/debug"
@@ -19,8 +18,6 @@ import (
text "text/template"
"time"
- "gitea.hashru.nl/dsprenkels/rushlink/internal/db"
-
"github.com/pkg/errors"
)
@@ -168,22 +165,6 @@ func (rl *rushlink) renderInternalServerError(w http.ResponseWriter, r *http.Req
rl.renderError(w, r, http.StatusInternalServerError, msg)
}
-func (rl *rushlink) renderCreateSuccess(w http.ResponseWriter, r *http.Request, paste *db.Paste, fu *db.FileUpload) {
- if paste == nil {
- panic("paste should not be nil")
- }
- var fileExt string
- if fu != nil {
- fileExt = fu.Ext()
- }
- var redirectURL url.URL
- redirectURL.Path = fmt.Sprintf("/%s%s/meta", paste.Key, fileExt)
- queryVals := redirectURL.Query()
- queryVals.Add("deleteToken", paste.DeleteToken)
- redirectURL.RawQuery = queryVals.Encode()
- http.Redirect(w, r, redirectURL.String(), http.StatusFound)
-}
-
// resolveHost constructs the `scheme://host` part of rushlinks public API.
//
// If the `--host` flag is set, it will return that URL.