mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-01-23 11:14:48 +02:00
105 lines
2.2 KiB
Go
105 lines
2.2 KiB
Go
package gonanoid
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"math"
|
|
)
|
|
|
|
// DefaultsType is the type of the default configuration for Nanoid
|
|
type DefaultsType struct {
|
|
Alphabet string
|
|
Size int
|
|
MaskSize int
|
|
}
|
|
|
|
// GetDefaults returns the default configuration for Nanoid
|
|
func GetDefaults() *DefaultsType {
|
|
return &DefaultsType{
|
|
Alphabet: "_~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", // len=64
|
|
Size: 22,
|
|
MaskSize: 5,
|
|
}
|
|
}
|
|
|
|
var defaults = GetDefaults()
|
|
|
|
func initMasks(params ...int) []uint {
|
|
var size int
|
|
if len(params) == 0 {
|
|
size = defaults.MaskSize
|
|
} else {
|
|
size = params[0]
|
|
}
|
|
masks := make([]uint, size)
|
|
for i := 0; i < size; i++ {
|
|
shift := 3 + i
|
|
masks[i] = (2 << uint(shift)) - 1
|
|
}
|
|
return masks
|
|
}
|
|
|
|
func getMask(alphabet string, masks []uint) int {
|
|
for i := 0; i < len(masks); i++ {
|
|
curr := int(masks[i])
|
|
if curr >= len(alphabet)-1 {
|
|
return curr
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Random generates cryptographically strong pseudo-random data.
|
|
// The size argument is a number indicating the number of bytes to generate.
|
|
func Random(size int) ([]byte, error) {
|
|
var randomBytes = make([]byte, size)
|
|
_, err := rand.Read(randomBytes)
|
|
return randomBytes, err
|
|
}
|
|
|
|
// Generate is a low-level function to change alphabet and ID size.
|
|
func Generate(alphabet string, size int) (string, error) {
|
|
masks := initMasks(size)
|
|
mask := getMask(alphabet, masks)
|
|
ceilArg := 1.6 * float64(mask*size) / float64(len(alphabet))
|
|
step := int(math.Ceil(ceilArg))
|
|
|
|
id := make([]byte, size)
|
|
bytes := make([]byte, step)
|
|
for j := 0; ; {
|
|
_, err := rand.Read(bytes)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
for i := 0; i < step; i++ {
|
|
currByte := bytes[i] & byte(mask)
|
|
if currByte < byte(len(alphabet)) {
|
|
id[j] = alphabet[currByte]
|
|
j++
|
|
if j == size {
|
|
return string(id[:size]), nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nanoid generates secure URL-friendly unique ID.
|
|
func Nanoid(param ...int) (string, error) {
|
|
var size int
|
|
if len(param) == 0 {
|
|
size = defaults.Size
|
|
} else {
|
|
size = param[0]
|
|
}
|
|
bytes := make([]byte, size)
|
|
_, err := rand.Read(bytes)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
id := make([]byte, size)
|
|
for i := 0; i < size; i++ {
|
|
id[i] = defaults.Alphabet[bytes[i]&63]
|
|
}
|
|
return string(id[:size]), nil
|
|
}
|