| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- 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
- }
|