parent
6d3e8028cb
commit
26be9b5104
11
handlers.go
11
handlers.go
@ -98,7 +98,7 @@ func (rl *rushlink) viewPasteHandlerFlags(w http.ResponseWriter, r *http.Request
|
||||
key := vars["key"]
|
||||
var p *db.Paste
|
||||
var fu *db.FileUpload
|
||||
if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
|
||||
err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
|
||||
var err error
|
||||
p, err = db.GetPaste(tx, key)
|
||||
if err != nil {
|
||||
@ -113,12 +113,13 @@ func (rl *rushlink) viewPasteHandlerFlags(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
})
|
||||
if err != nil {
|
||||
status := db.ErrHTTPStatusCode(err)
|
||||
if status == http.StatusInternalServerError {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
rl.renderError(w, r, http.StatusNotFound, "url key not found in the database")
|
||||
rl.renderError(w, r, status, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
@ -53,6 +54,35 @@ const (
|
||||
PasteStateDeleted
|
||||
)
|
||||
|
||||
// minKeyLen specifies the mimimum length of a paste key.
|
||||
const minKeyLen = 4
|
||||
|
||||
var (
|
||||
// ErrKeyInvalidChar occurs when a key contains an invalid character.
|
||||
ErrKeyInvalidChar = errors.New("invalid character in key")
|
||||
// ErrKeyInvalidLength occurs when a key embeds a length that is incorrect.
|
||||
ErrKeyInvalidLength = errors.New("key length encoding is incorrect")
|
||||
// ErrPasteDoesNotExist occurs when a key does not exist in the database.
|
||||
ErrPasteDoesNotExist = errors.New("url key not found in the database")
|
||||
)
|
||||
|
||||
// ErrHTTPStatusCode returns the HTTP status code that should correspond to
|
||||
// the provided error.
|
||||
// server error, or false if it is not.
|
||||
func ErrHTTPStatusCode(err error) int {
|
||||
switch err {
|
||||
case nil:
|
||||
return 0
|
||||
case ErrKeyInvalidChar:
|
||||
return http.StatusNotFound
|
||||
case ErrKeyInvalidLength:
|
||||
return http.StatusNotFound
|
||||
case ErrPasteDoesNotExist:
|
||||
return http.StatusNotFound
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
// Base64 encoding and decoding
|
||||
var base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
var base64Encoder = base64.RawURLEncoding.WithPadding(base64.NoPadding)
|
||||
@ -87,13 +117,45 @@ func (t PasteState) String() string {
|
||||
|
||||
// GetPaste retrieves a paste from the database.
|
||||
func GetPaste(tx *bolt.Tx, key string) (*Paste, error) {
|
||||
if err := ValidatePasteKey(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetPasteNoValidate(tx, key)
|
||||
}
|
||||
|
||||
// ValidatePasteKey validates the format of the key that has
|
||||
func ValidatePasteKey(key string) error {
|
||||
internalLen := minKeyLen
|
||||
countingOnes := true
|
||||
for _, ch := range key {
|
||||
limb := strings.IndexRune(base64Alphabet, ch)
|
||||
if limb == -1 {
|
||||
return ErrKeyInvalidChar
|
||||
}
|
||||
for i := 5; i >= 0 && countingOnes; i-- {
|
||||
if (limb>>uint(i))&0x1 == 0 {
|
||||
countingOnes = false
|
||||
break
|
||||
}
|
||||
internalLen++
|
||||
}
|
||||
}
|
||||
if internalLen != len(key) {
|
||||
return ErrKeyInvalidLength
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPasteNoValidate retrieves a paste from the database without validating
|
||||
// the key format first.
|
||||
func GetPasteNoValidate(tx *bolt.Tx, key string) (*Paste, error) {
|
||||
pastesBucket := tx.Bucket([]byte(BucketPastes))
|
||||
if pastesBucket == nil {
|
||||
return nil, errors.Errorf("bucket %v does not exist", BucketPastes)
|
||||
}
|
||||
storedBytes := pastesBucket.Get([]byte(key))
|
||||
if storedBytes == nil {
|
||||
return nil, nil
|
||||
return nil, ErrPasteDoesNotExist
|
||||
}
|
||||
return decodePaste(storedBytes)
|
||||
}
|
||||
@ -214,7 +276,6 @@ func GeneratePasteKey(tx *bolt.Tx, minimumEntropy int) (string, error) {
|
||||
// is used to ensure that a new key has at least some amount of guessing
|
||||
// entropy.
|
||||
func generatePasteKeyInner(epoch, entropy int) (string, error) {
|
||||
minKeyLen := 4
|
||||
entropyEpoch := entropy
|
||||
entropyEpoch -= minKeyLen * 6 // First 4 characters provide 24 bits.
|
||||
entropyEpoch++ // One bit less because of '0' bit.
|
||||
|
Loading…
Reference in New Issue
Block a user