Skip to content

Commit

Permalink
Merge branch 'master' of ssh://github.com/infobloxopen/atlas-app-tool…
Browse files Browse the repository at this point in the history
…kit into gateway-v2
  • Loading branch information
Calebjh committed Jul 22, 2021
2 parents 1b49ed5 + b5a8aff commit bbef708
Show file tree
Hide file tree
Showing 12 changed files with 988 additions and 84 deletions.
78 changes: 78 additions & 0 deletions bloxid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# BloxID

This package, bloxid, implements typed guids for identifying resource objects globally in the system. Resources are not specific to services/applications but must contain an entity type.

Typed guids have the advantage of being globally unique, easily readable, and strongly typed for authorization and logging. The trailing characters provide sufficient entropy to make each resource universally unique.

bloxid package provides methods for generating and parsing versioned typed guids.

bloxid supports different schemes for the unique id portion of the bloxid
- `extrinsic`
- `hashid`
- `random`


## Scheme - extrinsic

create bloxid from extrinsic id
```golang
v0, err := NewV0("",
WithEntityDomain("iam"),
WithEntityType("user"),
WithRealm("us-com-1"),
WithExtrinsic("123456"),
)
// v0.String(): blox0.iam.user.us-com-1.ivmfiurrgiztinjweaqcaiba
// v0.Decoded(): "123456"
```

parse bloxid to retrieve extrinsic id
```golang
parsed, err := NewV0("blox0.iam.user.us-com-1.ivmfiurrgiztinjweaqcaiba")
// v0.Decoded(): 1
```


## Scheme - hashid

create bloxid from hashid
```golang
v0, err := NewV0("",
WithEntityDomain("infra"),
WithEntityType("host"),
WithRealm("us-com-1"),
WithHashIDInt64(1),
WithHashIDSalt("test"),
)
// v0.String(): blox0.infra.host.us-com-1.jbeuiwrsmq3tkmzwmuzwcojsmrqwemrtgy3tqzbvhbsdizjvhe2dkn3cgzrdizlb
// v0.HashIDInt64(): 1
```

parse bloxid to retrieve hashid
```golang
parsed, err := NewV0("blox0.infra.host.us-com-1.jbeuiwrsmq3tkmzwmuzwcojsmrqwemrtgy3tqzbvhbsdizjvhe2dkn3cgzrdizlb",
WithHashIDSalt("test")
)
// v0.HashIDInt64(): 1
```


## Scheme - random

create bloxid from generated random id
```golang
v0, err := NewV0("",
WithEntityDomain("iam"),
WithEntityType("group"),
WithRealm("us-com-1"),
)
// v0.String(): blox0.iam.group.us-com-1.tshwyq3mfkgqqcfa76a5hbr2uaayzw3h
// v0.Decoded(): "9c8f6c436c2a8d0808a0ff81d3863aa0018cdb67"
```

parse bloxid to retrieve extrinsic id
```golang
parsed, err := NewV0("blox0.iam.group.us-com-1.tshwyq3mfkgqqcfa76a5hbr2uaayzw3h")
// v0.Decoded(): "9c8f6c436c2a8d0808a0ff81d3863aa0018cdb67"
```

49 changes: 49 additions & 0 deletions bloxid/extrinsicids.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package bloxid

import (
"errors"
"regexp"
)

const (
IDSchemeExtrinsic = "extrinsic"

extrinsicIDPrefix = "EXTR" //the prefix needs to be uppercase
)

var (
extrinsicIDPrefixBytes = []byte(extrinsicIDPrefix)

ErrEmptyExtrinsicID = errors.New("empty extrinsic id")
ErrInvalidExtrinsicID = errors.New("invalid extrinsic id")

extrinsicIDRegex = regexp.MustCompile(`^[0-9A-Za-z_-]+$`)
)

// WithExtrinsicID supplies a locally unique ID that is not randomly generated
func WithExtrinsicID(eid string) func(o *V0Options) {
return func(o *V0Options) {
o.extrinsicID = eid
o.scheme = IDSchemeExtrinsic
}
}

func validateGetExtrinsicID(id string) error {
if len(id) < 1 {
return ErrEmptyExtrinsicID
}

if !extrinsicIDRegex.MatchString(id) {
return ErrInvalidExtrinsicID
}

return nil
}

func getExtrinsicID(id string) (string, error) {
if err := validateGetExtrinsicID(id); err != nil {
return "", err
}

return id, nil
}
110 changes: 110 additions & 0 deletions bloxid/hashids.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package bloxid

import (
"errors"

hashids "github.com/speps/go-hashids/v2"
)

const (
IDSchemeHashID = "hashid"

hashIDAllowedChar = "0123456789abcdef"

//the prefix needs to be uppercase so there are no collisions with chars in hashIDAllowedChar
hashIDPrefix = "HIDZ"
)

var (
ErrInvalidSalt = errors.New("invalid salt")
ErrInvalidID = errors.New("invalid id")

maxHashIDLen = DefaultUniqueIDDecodedCharSize - len(hashIDPrefix)

hashIDPrefixBytes = []byte(hashIDPrefix)
)

func newHashID(salt string) (*hashids.HashID, error) {
hid := hashids.HashIDData{
Alphabet: hashIDAllowedChar,
MinLength: maxHashIDLen,
Salt: salt,
}

return hashids.NewWithData(&hid)
}

func validateGetHashID(id int64, salt string) error {

if len(salt) < 1 {
return ErrInvalidSalt
}

if id < 0 {
return ErrInvalidID
}

return nil
}

func getHashID(id int64, salt string) (string, error) {
if err := validateGetHashID(id, salt); err != nil {
return "", err
}

h, err := newHashID(salt)
if err != nil {
return "", err
}

eID, err := h.EncodeInt64([]int64{id})
if err != nil {
return "", err
}

return eID, err
}

func validateGetint64FromHashID(id, salt string) error {

if len(salt) < 1 {
return ErrInvalidSalt
}

if len(id) != maxHashIDLen {
return ErrInvalidID
}

return nil
}

func getInt64FromHashID(id, salt string) (int64, error) {
if err := validateGetint64FromHashID(id, salt); err != nil {
return -1, err
}

h, err := newHashID(salt)
if err != nil {
return -1, err
}

dID, err := h.DecodeInt64WithError(id)
if err != nil {
return -1, err
}

return dID[0], err
}

func WithHashIDInt64(id int64) func(o *V0Options) {
return func(o *V0Options) {
o.hashIDInt64 = id
o.scheme = IDSchemeHashID
}
}

func WithHashIDSalt(salt string) func(o *V0Options) {
return func(o *V0Options) {
o.hashidSalt = salt
}
}
Loading

0 comments on commit bbef708

Please sign in to comment.