From 838f09c20f948fbf55aade9f64acb4efdc243af3 Mon Sep 17 00:00:00 2001 From: Sander Pick Date: Thu, 7 May 2020 09:10:23 -0700 Subject: [PATCH] collections: ensure URL-safe collection names (#340) Signed-off-by: Sander Pick --- db/collection.go | 4 ++++ db/collection_test.go | 14 ++++++++++++-- db/db.go | 10 ++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/db/collection.go b/db/collection.go index ce6727b5..06a3eca4 100644 --- a/db/collection.go +++ b/db/collection.go @@ -46,6 +46,10 @@ type Collection struct { } func newCollection(name string, schema *jsonschema.Schema, d *DB) (*Collection, error) { + if name != "" && !collectionNameRx.MatchString(name) { + return nil, ErrInvalidCollectionName + } + // by default, use top level properties to validate ID string property exists properties := schema.Properties if schema.Ref != "" { diff --git a/db/collection_test.go b/db/collection_test.go index 58cc5da6..c6d994fb 100644 --- a/db/collection_test.go +++ b/db/collection_test.go @@ -99,6 +99,18 @@ func TestNewCollection(t *testing.T) { t.Fatal("the collection should be invalid") } }) + t.Run("Fail/InvalidName", func(t *testing.T) { + t.Parallel() + db, clean := createTestDB(t) + defer clean() + cc := CollectionConfig{ + Name: "Not a URL-safe name", + Schema: util.SchemaFromInstance(&Dog{}, false), + } + if _, err := db.NewCollection(cc); err != ErrInvalidCollectionName { + t.Fatal("the collection name should be invalid") + } + }) } func TestAddIndex(t *testing.T) { @@ -187,7 +199,6 @@ func TestCreateInstance(t *testing.T) { assertPersonInCollection(t, collection, newPerson1) assertPersonInCollection(t, collection, newPerson2) }) - t.Run("WithDefinedID", func(t *testing.T) { t.Parallel() db, clean := createTestDB(t) @@ -210,7 +221,6 @@ func TestCreateInstance(t *testing.T) { } assertPersonInCollection(t, collection, newPerson) }) - t.Run("Re-Create", func(t *testing.T) { t.Parallel() db, clean := createTestDB(t) diff --git a/db/db.go b/db/db.go index ed65d246..56a39828 100644 --- a/db/db.go +++ b/db/db.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + "regexp" "sync" "time" @@ -39,11 +40,20 @@ var ( // ErrInvalidCollectionSchema indicates the provided schema isn't valid for a Collection. ErrInvalidCollectionSchema = errors.New("the collection schema should specify an _id string property") + // ErrInvalidCollectionName indicates the provided name isn't valid for a Collection. + ErrInvalidCollectionName = errors.New("collection name may only contain alphanumeric characters or non-consecutive hyphens, and cannot begin or end with a hyphen") + + collectionNameRx *regexp.Regexp + dsDBPrefix = ds.NewKey("/db") dsDBSchemas = dsDBPrefix.ChildString("schema") dsDBIndexes = dsDBPrefix.ChildString("index") ) +func init() { + collectionNameRx = regexp.MustCompile(`^[A-Za-z0-9]+(?:[-][A-Za-z0-9]+)*$`) +} + // DB is the aggregate-root of events and state. External/remote events // are dispatched to the DB, and are internally processed to impact collection // states. Likewise, local changes in collections registered produce events dispatched