parent
1c09bb0a71
commit
6d3e8028cb
20
handlers.go
20
handlers.go
@ -22,6 +22,20 @@ const (
|
|||||||
// formParseMaxMemory value is based on the default value that is used in
|
// formParseMaxMemory value is based on the default value that is used in
|
||||||
// Request.ParseMultipartForm.
|
// Request.ParseMultipartForm.
|
||||||
formParseMaxMemory = 32 << 20 // 32 MB
|
formParseMaxMemory = 32 << 20 // 32 MB
|
||||||
|
|
||||||
|
// highOnlineEntropy is the desired entropy of an "unguessable" paste URL
|
||||||
|
// (in bits). It should be chosen such that it should be hard for an
|
||||||
|
// attacker to find *any* key that should not be found.
|
||||||
|
// It is desired that the probability to guess a good key is small.
|
||||||
|
//
|
||||||
|
// [ amount of pastes ]
|
||||||
|
// Pr[ good key ] = ---------------------------
|
||||||
|
// [ amount of possible keys ]
|
||||||
|
//
|
||||||
|
// So with a conservative [ amount of pastes ] = 2^32 (= 4 billion), and
|
||||||
|
// an [ amount of possible keys ] = 2^80 then the probability of a correct
|
||||||
|
// guess is 2^-48.
|
||||||
|
highOnlineEntropy = 80
|
||||||
)
|
)
|
||||||
|
|
||||||
type viewPaste uint
|
type viewPaste uint
|
||||||
@ -369,7 +383,11 @@ func shortenURL(tx *bolt.Tx, userURL *url.URL) (*db.Paste, error) {
|
|||||||
// Add a paste (of any kind) to the database with arbitrary content.
|
// Add a paste (of any kind) to the database with arbitrary content.
|
||||||
func shorten(tx *bolt.Tx, ty db.PasteType, content []byte) (*db.Paste, error) {
|
func shorten(tx *bolt.Tx, ty db.PasteType, content []byte) (*db.Paste, error) {
|
||||||
// Generate the paste key
|
// Generate the paste key
|
||||||
pasteKey, err := db.GeneratePasteKey(tx)
|
var keyEntropy int
|
||||||
|
if ty == db.PasteTypeFileUpload || ty == db.PasteTypePaste {
|
||||||
|
keyEntropy = highOnlineEntropy
|
||||||
|
}
|
||||||
|
pasteKey, err := db.GeneratePasteKey(tx, keyEntropy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "generating paste key")
|
return nil, errors.Wrap(err, "generating paste key")
|
||||||
}
|
}
|
||||||
|
@ -164,10 +164,13 @@ func (p *Paste) RedirectURL() *url.URL {
|
|||||||
return urlParse
|
return urlParse
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePasteKey generates a key until it is not in the database, the
|
// GeneratePasteKey generates a new paste key. It will ensure that the newly
|
||||||
// running time of this function is in O(log N), where N is the amount of
|
// generated paste key does not already exist in the database.
|
||||||
|
// The running time of this function is in O(log N), where N is the amount of
|
||||||
// keys stored in the url-shorten database.
|
// keys stored in the url-shorten database.
|
||||||
func GeneratePasteKey(tx *bolt.Tx) (string, error) {
|
// In tx, a Bolt transaction is given. Use minimumEntropy to set the mimimum
|
||||||
|
// guessing entropy of the generated key.
|
||||||
|
func GeneratePasteKey(tx *bolt.Tx, minimumEntropy int) (string, error) {
|
||||||
pastesBucket := tx.Bucket([]byte(BucketPastes))
|
pastesBucket := tx.Bucket([]byte(BucketPastes))
|
||||||
if pastesBucket == nil {
|
if pastesBucket == nil {
|
||||||
return "", errors.Errorf("bucket %v does not exist", BucketPastes)
|
return "", errors.Errorf("bucket %v does not exist", BucketPastes)
|
||||||
@ -177,7 +180,7 @@ func GeneratePasteKey(tx *bolt.Tx) (string, error) {
|
|||||||
var key string
|
var key string
|
||||||
for {
|
for {
|
||||||
var err error
|
var err error
|
||||||
key, err = generatePasteKeyInner(epoch)
|
key, err = generatePasteKeyInner(epoch, minimumEntropy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "url-key generation failed")
|
return "", errors.Wrap(err, "url-key generation failed")
|
||||||
}
|
}
|
||||||
@ -203,8 +206,23 @@ func GeneratePasteKey(tx *bolt.Tx) (string, error) {
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generatePasteKeyInner(epoch int) (string, error) {
|
// generatePasteKeyInner generates a new paste key, but leaves the
|
||||||
urlKey := make([]byte, 4+epoch)
|
// uniqueness and is-reserved checks to the caller. That is, it only
|
||||||
|
// generates a random key in the correct (syntactical) format.
|
||||||
|
// Both epoch and entropy can be used to set the key length. Epoch is used
|
||||||
|
// to prevent collisions in retrying to generate new keys. Entropy (in bits)
|
||||||
|
// 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.
|
||||||
|
entropyEpoch = (entropyEpoch-1)/5 + 1 // 5 bits for every added epoch.
|
||||||
|
if epoch < entropyEpoch {
|
||||||
|
epoch = entropyEpoch
|
||||||
|
}
|
||||||
|
urlKey := make([]byte, minKeyLen+epoch)
|
||||||
_, err := rand.Read(urlKey)
|
_, err := rand.Read(urlKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
Loading…
Reference in New Issue
Block a user