gonanoid.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package gonanoid
  2. import (
  3. "crypto/rand"
  4. "math"
  5. )
  6. // DefaultsType is the type of the default configuration for Nanoid
  7. type DefaultsType struct {
  8. Alphabet string
  9. Size int
  10. MaskSize int
  11. }
  12. // GetDefaults returns the default configuration for Nanoid
  13. func GetDefaults() *DefaultsType {
  14. return &DefaultsType{
  15. Alphabet: "_~0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", // len=64
  16. Size: 22,
  17. MaskSize: 5,
  18. }
  19. }
  20. var defaults = GetDefaults()
  21. func initMasks(params ...int) []uint {
  22. var size int
  23. if len(params) == 0 {
  24. size = defaults.MaskSize
  25. } else {
  26. size = params[0]
  27. }
  28. masks := make([]uint, size)
  29. for i := 0; i < size; i++ {
  30. shift := 3 + i
  31. masks[i] = (2 << uint(shift)) - 1
  32. }
  33. return masks
  34. }
  35. func getMask(alphabet string, masks []uint) int {
  36. for i := 0; i < len(masks); i++ {
  37. curr := int(masks[i])
  38. if curr >= len(alphabet)-1 {
  39. return curr
  40. }
  41. }
  42. return 0
  43. }
  44. // Random generates cryptographically strong pseudo-random data.
  45. // The size argument is a number indicating the number of bytes to generate.
  46. func Random(size int) ([]byte, error) {
  47. var randomBytes = make([]byte, size)
  48. _, err := rand.Read(randomBytes)
  49. return randomBytes, err
  50. }
  51. // Generate is a low-level function to change alphabet and ID size.
  52. func Generate(alphabet string, size int) (string, error) {
  53. masks := initMasks(size)
  54. mask := getMask(alphabet, masks)
  55. ceilArg := 1.6 * float64(mask*size) / float64(len(alphabet))
  56. step := int(math.Ceil(ceilArg))
  57. id := make([]byte, size)
  58. bytes := make([]byte, step)
  59. for j := 0; ; {
  60. _, err := rand.Read(bytes)
  61. if err != nil {
  62. return "", err
  63. }
  64. for i := 0; i < step; i++ {
  65. currByte := bytes[i] & byte(mask)
  66. if currByte < byte(len(alphabet)) {
  67. id[j] = alphabet[currByte]
  68. j++
  69. if j == size {
  70. return string(id[:size]), nil
  71. }
  72. }
  73. }
  74. }
  75. }
  76. // Nanoid generates secure URL-friendly unique ID.
  77. func Nanoid(param ...int) (string, error) {
  78. var size int
  79. if len(param) == 0 {
  80. size = defaults.Size
  81. } else {
  82. size = param[0]
  83. }
  84. bytes := make([]byte, size)
  85. _, err := rand.Read(bytes)
  86. if err != nil {
  87. return "", err
  88. }
  89. id := make([]byte, size)
  90. for i := 0; i < size; i++ {
  91. id[i] = defaults.Alphabet[bytes[i]&63]
  92. }
  93. return string(id[:size]), nil
  94. }