Skip to content

Commit

Permalink
Merge pull request #9 from akshayvadher/cli
Browse files Browse the repository at this point in the history
Cli
  • Loading branch information
akshayvadher authored Jul 19, 2024
2 parents e357f06 + de8af44 commit 293a748
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 6 deletions.
104 changes: 103 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,109 @@
# cuid2
Next generation guids. Secure, collision-resistant ids optimized for horizontal scaling and performance.

Next generation guids.
Secure, collision-resistant ids optimized for horizontal scaling and
performance.

Original author and reference: https://github.com/paralleldrive/cuid2

# package

```shell
go get github.com/akshayvadher/cuid2
```

## usage

```go
package main

import (
"fmt"
"github.com/akshayvadher/cuid2"
)

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

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

createId := cuid2.Init(customRandomFunction, customCounterFunction, length, customFingerprintString)
createId()
// this generates id with custom parameters
}
````

###

# cli

```shell
go install github.com/akshayvadher/cuid2/cmd/cuid2@latest
```

## usage

```shell
cuid2
# wldu51x7wn6baulkeq49qfm7
cuid2 -n 5
# generates 5 ids
# s7dseq8y5ti85c02eptzia1p
# wz4rk8nj39dpyd01gddsp9rz
# kwezj4wa69d6ta7jxg3b6lnz
# pzuju2hk01xpev6ixnnnsqba
# enxpfer2u7c00xa24li0jghc
cuid2 -len 10
# generates id with length 10
# h8crfzyp6q
cuid2 -n 3 -len 11
# generates 3 ids with length 11
# ijlk68norem
# redx1s0adbb
# mk5zg8dxgi1
cuid2 validate 123
# not a valid CUID2 "123"
cuid2 validate qf9183tmebd
# Valid CUID2 "qf9183tmebd"
```

# understanding
```mermaid
flowchart TD
A[Init] -->PARTS[Parts]
A -->I[Static]
I --> IC(Counter)
IC --> ICI(Random number\nfrom 1 to 476782367\nusing math.random\nas initial for counter\nExample: 284777857)
ICI --> ICV(Get next int\nfrom initial counter\nExample: 284777858)
ICV --> ICVS(String base 36 of counter\nExample: 4pjs02)
I --> FI(Fingerprint)
FI --> GLOBAL(Using ENV variable's keys \n+ process id \n+ entropy\nExample: PATH_JAVA_HOME_...32732joj7hxvuerwy2m8ogjjvya1sxnhryizp)
GLOBAL --> GLOBAL_HASH(That creates hash\nExample: p051cbjeehq8k4srz81f1k27qy5ug4xspl9qurcloe9v0ibzxygy39imhqzm6zuq3gxl9758k525jm9m1zy5zdb7b5mkrjbh3h)
GLOBAL_HASH --> GLOBAL_HASH_TRUNCATE(Trucate to the max len\nExample: p051cbjeehq8k4srz81f1k27qy5ug4xs)
PARTS --> RANDOM_CHAR(Random char from a to z)
PARTS --> HASH_PARTS(Hash parts)
RANDOM_CHAR --> RANDOM_CHAR_E(Using math.random\nExample: u)
HASH_PARTS --> TIME(Time millis\nExmaple: 1721287835377)
TIME --> TIME_STR(To string represenataion\nwith base 36 = 0-9 and a-z\nExample: lyqyc1yp)
HASH_PARTS --> SALT(Salt generation)
SALT --> ENTROPY(Creating entropy\nUsing chars of base36\nUsing math.random\nExample: gxrohhjf8t0c6j5zjoj05o9k)
TIME_STR --> COMBINE_HASH_INPUT(Combined Hash input\ntimeString + salt + count + fingerprint\nExample: lyqyc1ypgxrohhjf8t0c6j5zjoj05o9k4pjs02p051cbjeehq8k4srz81f1k27qy5ug4xs)
ENTROPY --> COMBINE_HASH_INPUT
ICVS --> COMBINE_HASH_INPUT
GLOBAL_HASH_TRUNCATE --> COMBINE_HASH_INPUT
COMBINE_HASH_INPUT --> SHA3(SHA3_512)
SHA3 --> BIG_INT(Big int of SHA3_512\nExample: 42ybcc5cg8oormscwq75cvckeprc888472wq54acxqcdj6sno2tgnsuz4dslxpib2fftsy0gax4va9vaw5oem2vosqrw82glqgh)
BIG_INT --> BIG_INT_1(Dropping first char due to bias\nExample: 2ybcc5cg8oormscwq75cvckeprc888472wq54acxqcdj6sno2tgnsuz4dslxpib2fftsy0gax4va9vaw5oem2vosqrw82glqgh)
BIG_INT_1 --> HASH_TAIL(Tail\nDropping first char and trimming till leng\nExample: ybcc5cg8oormscwq75cvcke)
RANDOM_CHAR_E --> OUTPUT(Output CUID2\nRandomLetter + hash of timeString + salt + count + fingerprint\nExample: uybcc5cg8oormscwq75cvcke)
HASH_TAIL --> OUTPUT
```
60 changes: 60 additions & 0 deletions cmd/cuid2/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"fmt"
"github.com/akshayvadher/cuid2"
"github.com/urfave/cli/v2"
"log"
"os"
)

func main() {
app := &cli.App{
Name: "cuid2",
Usage: "Create CUID2",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "n",
Value: 1,
Usage: "Numbers of ids to generate",
},
&cli.IntFlag{
Name: "len",
Value: 24,
Usage: "Length of the Id (between 2 and 32)",
Action: func(ctx *cli.Context, v int) error {
if v > 32 || v < 2 {
return fmt.Errorf("len %v should be between 2 and 32", v)
}
return nil
},
},
},
Action: func(cCtx *cli.Context) error {
for range cCtx.Int("n") {
fmt.Println(cuid2.CreateIdOf(cCtx.Int("len")))
}
return nil
},
Commands: []*cli.Command{
{
Name: "validate",
Usage: "Validate whether provided CUIID2 is valid or not",
Action: func(cCtx *cli.Context) error {
argCuid2 := cCtx.Args().First()
if argCuid2 == "" {
return fmt.Errorf("expected argument to validate command")
}
if !cuid2.IsCuid(argCuid2) {
return fmt.Errorf("not a valid CUID2 %q", argCuid2)
}
fmt.Printf("Valid CUID2 %q", argCuid2)
return nil
},
},
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
20 changes: 17 additions & 3 deletions cuid2.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var (
DefaultCounter func() int64
DefaultFingerprint string
defaultInit func() string
envVariableKeys string
cuidRegex = regexp.MustCompile("^[a-z][0-9a-z]+$")
)

Expand All @@ -31,11 +32,22 @@ const (
)

func init() {
envVariableKeys = strings.Join(getEnvVariableKeys(), "_")
DefaultCounter = createCounter(int64(DefaultRandom() * initialCountMax))
DefaultFingerprint = createFingerprint(DefaultRandom)
defaultInit = Init(DefaultRandom, DefaultCounter, defaultLength, DefaultFingerprint)
}

func getEnvVariableKeys() []string {
var ek []string
for _, e := range os.Environ() {
if i := strings.Index(e, "="); i >= 0 {
ek = append(ek, e[:i])
}
}
return ek
}

func randomLetter(random func() float64) string {
return alphabet[int(random()*float64(len(alphabet)))]
}
Expand All @@ -55,10 +67,8 @@ func hash(input string) string {
}

func createFingerprint(random func() float64) string {
host, _ := os.Hostname()
userHome, _ := os.UserHomeDir()
pid := os.Getpid()
globals := host + userHome + string(rune(pid))
globals := envVariableKeys + strconv.Itoa(pid)
sourceString := globals + createEntropy(bigLength, random)

return hash(sourceString)[:bigLength]
Expand Down Expand Up @@ -106,6 +116,10 @@ func CreateId() string {
return defaultInit()
}

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

func IsCuid(id string) bool {
minLength := 2
maxLength := bigLength
Expand Down
16 changes: 15 additions & 1 deletion cuid2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestConfigurability(t *testing.T) {
}
}

func TestLength(t *testing.T) {
func TestLengthWithFullCustomization(t *testing.T) {
minLen := 2
maxLen := 32
for tt := minLen; tt <= maxLen; tt++ {
Expand All @@ -116,3 +116,17 @@ func TestLength(t *testing.T) {
})
}
}

func TestLengthOnlyCustomization(t *testing.T) {
minLen := 2
maxLen := 32
for tt := minLen; tt <= maxLen; tt++ {
t.Run(fmt.Sprintf("with length %d", tt), func(t *testing.T) {
id := CreateIdOf(tt)
fmt.Printf("Created id %q\n", id)
if len(id) != tt {
t.Errorf("Expected id of len %d. Got %d\n", tt, len(id))
}
})
}
}
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ go 1.22.2

require golang.org/x/crypto v0.25.0

require golang.org/x/sys v0.22.0 // indirect
require (
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/urfave/cli/v2 v2.27.2 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
golang.org/x/sys v0.22.0 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
Expand Down

0 comments on commit 293a748

Please sign in to comment.