Skip to content
Snippets Groups Projects
random.go 1.08 KiB
package util

import (
	"crypto/rand"

	"owo.codes/whats-this/api/lib/db"

	"github.com/pkg/errors"
	"github.com/akamensky/base58"
)

// GenerateRandomKey generates a cryptographically secure 7 character base 58
// string for object keys.
func GenerateRandomKey() (string, error) {
	data := make([]byte, 7)
	_, err := rand.Read(data)
	if err != nil {
		return "", err
	}
	str := base58.Encode(data)
	if len(str) >= 7 {
		return str[0:7], nil
	}
	return GenerateRandomKey()
}

// GenerateAvailableKey runs GenerateRandomKey and verifies that the generated
// key isn't already being used.
func GenerateAvailableKey(maxAttempts int) (string, error) {
	for n := 0; n < maxAttempts; n++ {
		key, err := GenerateRandomKey()
		if err != nil {
			return "", errors.Wrap(err, "failed to generate random key")
		}

		exists, err := db.ObjectKeyExists(key)
		if err != nil {
			return "", errors.Wrapf(err, `failed to check if object exists with key "%s"`, key)
		}
		if exists {
			continue
		}
		return key, nil
	}
	return "", errors.Errorf("failed to generate an available key within %v attempts", maxAttempts)
}