Add ability to generate pseudo-random IDs (#984)

pull/1006/head
Jeff Mitchell 5 years ago committed by GitHub
parent d456893f63
commit bb2d86eb39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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
}
}

Loading…
Cancel
Save