Use high-entropy URLs for file uploads

Fixes issue #59
This commit is contained in:
Daan Sprenkels
2020-07-27 14:53:19 +02:00
parent 1c09bb0a71
commit 6d3e8028cb
2 changed files with 43 additions and 7 deletions

View File

@@ -164,10 +164,13 @@ func (p *Paste) RedirectURL() *url.URL {
return urlParse
}
// GeneratePasteKey generates a key until it is not in the database, the
// running time of this function is in O(log N), where N is the amount of
// GeneratePasteKey generates a new paste key. It will ensure that the newly
// 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.
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))
if pastesBucket == nil {
return "", errors.Errorf("bucket %v does not exist", BucketPastes)
@@ -177,7 +180,7 @@ func GeneratePasteKey(tx *bolt.Tx) (string, error) {
var key string
for {
var err error
key, err = generatePasteKeyInner(epoch)
key, err = generatePasteKeyInner(epoch, minimumEntropy)
if err != nil {
return "", errors.Wrap(err, "url-key generation failed")
}
@@ -203,8 +206,23 @@ func GeneratePasteKey(tx *bolt.Tx) (string, error) {
return key, nil
}
func generatePasteKeyInner(epoch int) (string, error) {
urlKey := make([]byte, 4+epoch)
// generatePasteKeyInner generates a new paste key, but leaves the
// 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)
if err != nil {
return "", err