Skip to content

Commit

Permalink
Added len validations at CreateIdOf (#11)
Browse files Browse the repository at this point in the history
* Fix: Invalid len of CUID2

* Updated: Moved validation to Init() function | Change in Tests | Updated README Accordingly
  • Loading branch information
omjogani authored Jul 19, 2024
1 parent 293a748 commit e38df90
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 20 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
)

func main() {
id := cuid2.CreateId()
id, err := cuid2.CreateId()
fmt.Println(id)
// to create default length id
// us1hfvvf2uyzmh031bav6skw

idWithLength := cuid2.CreateIdOf(10)
idWithLength, err := cuid2.CreateIdOf(10)
// zev57ezp7c

createId := cuid2.Init(customRandomFunction, customCounterFunction, length, customFingerprintString)
Expand Down
21 changes: 15 additions & 6 deletions cuid2.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cuid2

import (
"errors"
"golang.org/x/crypto/sha3"
"math"
"math/big"
Expand All @@ -17,7 +18,7 @@ var (
DefaultRandom = rand.Float64
DefaultCounter func() int64
DefaultFingerprint string
defaultInit func() string
defaultInit func() (string, error)
envVariableKeys string
cuidRegex = regexp.MustCompile("^[a-z][0-9a-z]+$")
)
Expand Down Expand Up @@ -91,8 +92,16 @@ func createEntropy(length int, random func() float64) string {
return entropy.String()
}

func Init(random func() float64, counter func() int64, length int, fingerprint string) func() string {
return func() string {
func Init(random func() float64, counter func() int64, length int, fingerprint string) func() (string, error) {
return func() (string, error) {
minLength := 2
maxLength := bigLength

// Ensure length is between 2 and 32
if length < minLength || length > maxLength {
return "", errors.New("len should be between 2 and 32")
}

firstLetter := randomLetter(random)

// If we're lucky, the base 36 conversion calls may reduce hashing rounds
Expand All @@ -108,15 +117,15 @@ func Init(random func() float64, counter func() int64, length int, fingerprint s
hash := hash(hashInput)

cuid2 := firstLetter + hash[1:length]
return cuid2
return cuid2, nil
}
}

func CreateId() string {
func CreateId() (string, error) {
return defaultInit()
}

func CreateIdOf(len int) string {
func CreateIdOf(len int) (string, error) {
return Init(DefaultRandom, DefaultCounter, len, DefaultFingerprint)()
}

Expand Down
4 changes: 2 additions & 2 deletions cuid2_collision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func createIdPool(t *testing.T, max int, poolId int, idPoolResponseChan chan *Id
defer wg.Done()
set := make(map[string]struct{}, max)
for i := 0; i < max; i++ {
id := CreateId()
if !IsCuid(id) {
id, err := CreateId()
if !IsCuid(id) && err != nil {
t.Errorf("The id %s is not a CUID", id)
break
}
Expand Down
46 changes: 36 additions & 10 deletions cuid2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

func create(t *testing.T) string {
id := CreateId()
if id == "" {
id, err := CreateId()
if id == "" || err != nil {
t.Fatalf("Cuid not generated")
}
if len(id) != 24 {
Expand Down Expand Up @@ -42,8 +42,18 @@ func TestFirstCharFromAtoZ(t *testing.T) {
func TestIsCuidFalse(t *testing.T) {
tests := []string{
"", "1", "1", "asdf98923jhf90283jh02983hjf02983fh", "afasd as dfas ", "1asdfasdf", " ",
CreateId() + CreateId() + CreateId(),
}

combinationOfCuids := ""
for i := 0; i < 3; i++ {
id, err := CreateId()
if err != nil {
t.Fatalf("Failed to create CUID: %v", err)
}
combinationOfCuids += id
}
tests = append(tests, combinationOfCuids)

for _, tt := range tests {
t.Run(tt, func(t *testing.T) {
isCuid := IsCuid(tt)
Expand Down Expand Up @@ -77,7 +87,11 @@ func TestIsCuidWithValidIds(t *testing.T) {
func FuzzTestRandom(f *testing.F) {
noOfIdsToGenerate := 1000
for range noOfIdsToGenerate {
f.Add(CreateId())
id, err := CreateId()
if err != nil {
f.Fatalf("Failed to create CUID: %v", err)
}
f.Add(id)
}

f.Fuzz(func(t *testing.T, id string) {
Expand All @@ -93,8 +107,8 @@ func TestConfigurability(t *testing.T) {
length := 3
fingerprint := "abc"
fn := Init(random, counter, length, fingerprint)
id := fn()
if id == "" {
id, err := fn()
if id == "" || err != nil {
t.Errorf("Custom function didn't return proper id")
}
if len(id) != 3 {
Expand All @@ -108,9 +122,9 @@ func TestLengthWithFullCustomization(t *testing.T) {
for tt := minLen; tt <= maxLen; tt++ {
t.Run(fmt.Sprintf("with length %d", tt), func(t *testing.T) {
createId := Init(DefaultRandom, DefaultCounter, tt, DefaultFingerprint)
id := createId()
id, err := createId()
fmt.Printf("Created id %q\n", id)
if len(id) != tt {
if len(id) != tt || err != nil {
t.Errorf("Expected id of len %d. Got %d\n", tt, len(id))
}
})
Expand All @@ -122,11 +136,23 @@ func TestLengthOnlyCustomization(t *testing.T) {
maxLen := 32
for tt := minLen; tt <= maxLen; tt++ {
t.Run(fmt.Sprintf("with length %d", tt), func(t *testing.T) {
id := CreateIdOf(tt)
id, err := CreateIdOf(tt)
fmt.Printf("Created id %q\n", id)
if len(id) != tt {
if len(id) != tt || err != nil {
t.Errorf("Expected id of len %d. Got %d\n", tt, len(id))
}
})
}
}

func TestInvalidLength(t *testing.T) {
tests := []int{1, 33, 0, -1}
for _, tt := range tests {
t.Run(fmt.Sprintf("with length %d", tt), func(t *testing.T) {
id, err := CreateIdOf(tt)
if id != "" || err.Error() != "len should be between 2 and 32" {
t.Errorf("Expected error 'len should be between 2 and 32' and Empty ID but got %s with ID=%s\n", err.Error(), id)
}
})
}
}

0 comments on commit e38df90

Please sign in to comment.