Add ability to generate pseudo-random IDs (#984)
This commit is contained in:
1 parent
d456893f63
commit
bb2d86eb39
3 files changed
+78
-6
No files matched your search
+18
-6
@@ -1,27 +1,39 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/vault/sdk/helper/base62"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
)
|
||||
|
||||
func NewPrivateId(prefix string) (string, error) {
|
||||
return newId(prefix)
|
||||
func NewPrivateId(prefix string, opt ...Option) (string, error) {
|
||||
return newId(prefix, opt...)
|
||||
}
|
||||
|
||||
// NewPublicId creates a new public id with the prefix
|
||||
func NewPublicId(prefix string) (string, error) {
|
||||
return newId(prefix)
|
||||
func NewPublicId(prefix string, opt ...Option) (string, error) {
|
||||
return newId(prefix, opt...)
|
||||
}
|
||||
|
||||
func newId(prefix string) (string, error) {
|
||||
func newId(prefix string, opt ...Option) (string, error) {
|
||||
const op = "db.newId"
|
||||
if prefix == "" {
|
||||
return "", errors.New(errors.InvalidParameter, op, "missing prefix")
|
||||
}
|
||||
publicId, err := base62.Random(10)
|
||||
var publicId string
|
||||
var err error
|
||||
opts := GetOpts(opt...)
|
||||
if len(opts.withPrngValues) > 0 {
|
||||
sum := blake2b.Sum256([]byte(strings.Join(opts.withPrngValues, "|")))
|
||||
reader := bytes.NewReader(sum[0:])
|
||||
publicId, err = base62.RandomWithReader(10, reader)
|
||||
} else {
|
||||
publicId, err = base62.Random(10)
|
||||
}
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, op, errors.WithMsg("unable to generate id"), errors.WithCode(errors.Io))
|
||||
}
|
||||
|
||||
@@ -93,3 +93,53 @@ func TestNewPrivateId(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPseudoRandomId(t *testing.T) {
|
||||
type args struct {
|
||||
prngValues []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
sameAsPrev bool
|
||||
}{
|
||||
{
|
||||
name: "valid first",
|
||||
args: args{},
|
||||
},
|
||||
{
|
||||
name: "valid second",
|
||||
args: args{},
|
||||
},
|
||||
{
|
||||
name: "first prng",
|
||||
args: args{prngValues: []string{"foo", "bar"}},
|
||||
},
|
||||
{
|
||||
name: "first prng verify",
|
||||
args: args{prngValues: []string{"foo", "bar"}},
|
||||
sameAsPrev: true,
|
||||
},
|
||||
{
|
||||
name: "second prng",
|
||||
args: args{prngValues: []string{"bar", "foo"}},
|
||||
},
|
||||
{
|
||||
name: "second prng verify",
|
||||
args: args{prngValues: []string{"bar", "foo"}},
|
||||
sameAsPrev: true,
|
||||
},
|
||||
}
|
||||
var prevTestValue string
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, err := NewPublicId("id", WithPrngValues(tt.args.prngValues))
|
||||
require.NoError(err)
|
||||
if tt.sameAsPrev {
|
||||
assert.Equal(prevTestValue, got)
|
||||
}
|
||||
prevTestValue = got
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,9 @@ type Options struct {
|
||||
withWhereClause string
|
||||
withWhereClauseArgs []interface{}
|
||||
withOrder string
|
||||
|
||||
// withPrngValues is used to switch the ID generation to a pseudo-random mode
|
||||
withPrngValues []string
|
||||
}
|
||||
|
||||
type oplogOpts struct {
|
||||
@@ -155,3 +158,10 @@ func WithOrder(withOrder string) Option {
|
||||
o.withOrder = withOrder
|
||||
}
|
||||
}
|
||||
|
||||
// WithPrngValues provides an option to provide values to seed an PRNG when generating IDs
|
||||
func WithPrngValues(withPrngValues []string) Option {
|
||||
return func(o *Options) {
|
||||
o.withPrngValues = withPrngValues
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user