forked from electricdusk/rushlink
Show meta page immediately after create
This commit is contained in:
parent
c46a26f8a2
commit
3d07acb222
@ -6,8 +6,8 @@
|
|||||||
<pre>
|
<pre>
|
||||||
<a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}</a>
|
<a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}</a>
|
||||||
---
|
---
|
||||||
{{if and (ne .Paste.State.String "deleted") .CanDelete.Bool}}
|
{{if and (ne .Paste.State.String "deleted") .CanDeleteBool}}
|
||||||
with delete token: <a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}</a>
|
with delete token: <a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}</a>
|
||||||
{{else -}}
|
{{else -}}
|
||||||
with delete token: <unknown>
|
with delete token: <unknown>
|
||||||
{{end -}}
|
{{end -}}
|
||||||
@ -18,18 +18,11 @@ created: unknown
|
|||||||
{{else -}}
|
{{else -}}
|
||||||
created: {{.Paste.TimeCreated}}
|
created: {{.Paste.TimeCreated}}
|
||||||
{{end -}}
|
{{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:
|
curl --request "DELETE" "<a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"</a>
|
||||||
{{- /*
|
|
||||||
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" "<a href="{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}">{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}"</a>
|
|
||||||
```
|
```
|
||||||
</pre>
|
</pre>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{.Host}}/{{.Paste.Key}}{{.FileExt}}
|
{{.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"}}
|
with delete token: {{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Request.URL.Query.Get "deleteToken"}}
|
||||||
{{else -}}
|
{{else -}}
|
||||||
with delete token: <unknown>
|
with delete token: <unknown>
|
||||||
@ -11,17 +11,11 @@ created: unknown
|
|||||||
{{else -}}
|
{{else -}}
|
||||||
created: {{.Paste.TimeCreated}}
|
created: {{.Paste.TimeCreated}}
|
||||||
{{end -}}
|
{{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:
|
# To delete this {{.Paste.Type}}, execute:
|
||||||
{{- /*
|
curl --request "DELETE" "{{.Host}}/{{.Paste.Key}}{{.FileExt}}?deleteToken={{.Paste.DeleteToken}}"
|
||||||
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"}}"
|
|
||||||
```
|
```
|
||||||
{{end}}
|
{{end}}
|
||||||
|
113
handlers.go
113
handlers.go
@ -28,6 +28,31 @@ const (
|
|||||||
|
|
||||||
const cookieDeleteToken = "owner_token"
|
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) {
|
func (rl *rushlink) staticGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
rl.renderStatic(w, r, mux.Vars(r)["path"])
|
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) {
|
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) {
|
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) {
|
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)
|
vars := mux.Vars(r)
|
||||||
key := vars["key"]
|
key := vars["key"]
|
||||||
var p *db.Paste
|
var p *db.Paste
|
||||||
var fuID *uuid.UUID
|
|
||||||
var fu *db.FileUpload
|
var fu *db.FileUpload
|
||||||
var fileExt string
|
|
||||||
if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
|
if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
|
||||||
var err error
|
var err error
|
||||||
p, err = db.GetPaste(tx, key)
|
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 {
|
if p != nil && p.Type == db.PasteTypeFileUpload {
|
||||||
var id uuid.UUID
|
var id uuid.UUID
|
||||||
copy(id[:], p.Content)
|
copy(id[:], p.Content)
|
||||||
fuID = &id
|
|
||||||
fu, err = db.GetFileUpload(tx, id)
|
fu, err = db.GetFileUpload(tx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fileExt = fu.Ext()
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -123,30 +144,12 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags&viewShowMeta != 0 {
|
rl.viewPasteHandlerInner(w, r, flags, p, fu)
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data := map[string]interface{}{
|
func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request, flags viewPaste, p *db.Paste, fu *db.FileUpload) {
|
||||||
"Paste": p,
|
if flags&viewShowMeta != 0 {
|
||||||
"FileExt": fileExt,
|
rl.viewPasteHandlerInnerMeta(w, r, p, fu)
|
||||||
"CanDelete": canDelete,
|
|
||||||
}
|
|
||||||
rl.render(w, r, "pasteMeta", data)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.State {
|
switch p.State {
|
||||||
@ -155,7 +158,7 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
|
|||||||
switch p.Type {
|
switch p.Type {
|
||||||
case db.PasteTypeFileUpload:
|
case db.PasteTypeFileUpload:
|
||||||
if fu == nil {
|
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()
|
location = fu.URL().String()
|
||||||
break
|
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) {
|
func (rl *rushlink) newPasteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
file, fileHeader, err := r.FormFile("file")
|
file, fileHeader, err := r.FormFile("file")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -216,7 +259,7 @@ func (rl *rushlink) newFileUploadPasteHandler(w http.ResponseWriter, r *http.Req
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
panic(err)
|
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) {
|
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 {
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
rl.renderCreateSuccess(w, r, paste, nil)
|
rl.viewCreateSuccess(w, r, paste, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a URL from the database
|
// 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))
|
rl.renderError(w, r, errorCode, fmt.Sprintf("error: %v\n", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rl.renderCreateSuccess(w, r, paste, nil)
|
rl.viewCreateSuccess(w, r, paste, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new fileUpload redirect to the database
|
// Add a new fileUpload redirect to the database
|
||||||
|
19
views.go
19
views.go
@ -9,7 +9,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
@ -19,8 +18,6 @@ import (
|
|||||||
text "text/template"
|
text "text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"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)
|
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.
|
// resolveHost constructs the `scheme://host` part of rushlinks public API.
|
||||||
//
|
//
|
||||||
// If the `--host` flag is set, it will return that URL.
|
// If the `--host` flag is set, it will return that URL.
|
||||||
|
Loading…
Reference in New Issue
Block a user