3
0

Disallow use of reserved names for module fields

List of reserved names:
 - recordID
 - ownedBy
 - createdBy
 - createdAt
 - updatedBy
 - updatedAt
 - deletedBy
 - deletedAt
This commit is contained in:
Denis Arh
2021-10-21 13:20:50 +02:00
parent 0b69d1a2e3
commit 20757e58fa
4 changed files with 121 additions and 2 deletions

View File

@@ -17,6 +17,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/slice"
"github.com/cortezaproject/corteza-server/store"
)
@@ -63,6 +64,19 @@ const (
moduleFieldsChanged moduleChanges = 4
)
var (
systemFields = slice.ToStringBoolMap([]string{
"recordID",
"ownedBy",
"createdBy",
"createdAt",
"updatedBy",
"updatedAt",
"deletedBy",
"deletedAt",
})
)
func Module() *module {
return &module{
ac: DefaultAccessControl,
@@ -217,6 +231,16 @@ func (svc module) Create(ctx context.Context, new *types.Module) (*types.Module,
return ModuleErrInvalidHandle()
}
for _, f := range new.Fields {
if systemFields[f.Name] {
return ModuleErrFieldNameReserved()
}
}
if err != nil {
}
if ns, err = loadNamespace(ctx, s, new.NamespaceID); err != nil {
return err
}
@@ -574,6 +598,13 @@ func updateModuleFields(ctx context.Context, s store.Storer, new, old *types.Mod
f.NamespaceID = new.NamespaceID
}
if systemFields[f.Name] && !old.Fields.HasName(f.Name) {
// make sure we're backward compatible, or better:
// if, by some weird case, someone managed to get invalid field name into
// the store, we'll turn a blind eye.
return ModuleErrFieldNameReserved()
}
if f.ModuleID != new.ID {
return fmt.Errorf("module id of field %q does not match the module", f.Name)
}

View File

@@ -628,7 +628,7 @@ func ModuleErrNameNotUnique(mm ...*moduleActionProps) *errors.Error {
errors.Meta("resource", "compose:module"),
// action log entry; no formatting, it will be applied inside recordAction fn.
errors.Meta(moduleLogMetaKey{}, "used duplicate username ({{module.name}}) for module"),
errors.Meta(moduleLogMetaKey{}, "used duplicate name ({{module.name}}) for module"),
errors.Meta(modulePropsMetaKey{}, p),
// translation namespace & key
@@ -644,6 +644,40 @@ func ModuleErrNameNotUnique(mm ...*moduleActionProps) *errors.Error {
return e
}
// ModuleErrFieldNameReserved returns "compose:module.fieldNameReserved" as *errors.Error
//
//
// This function is auto-generated.
//
func ModuleErrFieldNameReserved(mm ...*moduleActionProps) *errors.Error {
var p = &moduleActionProps{}
if len(mm) > 0 {
p = mm[0]
}
var e = errors.New(
errors.KindInternal,
p.Format("field name is reserved for system fields", nil),
errors.Meta("type", "fieldNameReserved"),
errors.Meta("resource", "compose:module"),
errors.Meta(modulePropsMetaKey{}, p),
// translation namespace & key
errors.Meta(locale.ErrorMetaNamespace{}, "compose"),
errors.Meta(locale.ErrorMetaKey{}, "module.errors.fieldNameReserved"),
errors.StackSkip(1),
)
if len(mm) > 0 {
}
return e
}
// ModuleErrStaleData returns "compose:module.staleData" as *errors.Error
//
//

View File

@@ -71,9 +71,12 @@ errors:
- error: nameNotUnique
message: "name not unique"
log: "used duplicate username ({{module.name}}) for module"
log: "used duplicate name ({{module.name}}) for module"
severity: warning
- error: fieldNameReserved
message: "field name is reserved for system fields"
- error: staleData
message: "stale data"
severity: warning

View File

@@ -266,6 +266,57 @@ func TestModuleFieldsUpdate(t *testing.T) {
h.a.Equal(m.Fields[1].Kind, "DateTime")
}
func TestModuleUpdateWithReservedFieldName(t *testing.T) {
h := newHelper(t)
h.clearModules()
helpers.AllowMe(h, types.NamespaceRbacResource(0), "read", "modules.search")
ns := h.makeNamespace("some-namespace")
m := h.makeModule(ns, "some-module", &types.ModuleField{ID: id.Next(), Kind: "String", Name: "ownedBy"})
helpers.AllowMe(h, types.ModuleRbacResource(0, 0), "update")
f := m.Fields[0]
fjs := fmt.Sprintf(`{ "name": "%s", "fields": [{ "fieldID": "%d", "name": "ownedBy", "kind": "Number" }]}`, m.Name, f.ID)
h.apiInit().
Post(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)).
Header("Accept", "application/json").
JSON(fjs).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
f = m.Fields[0]
fjs = fmt.Sprintf(`{ "name": "%s", "fields": [{ "fieldID": "%d", "name": "updatedBy", "kind": "Number" }]}`, m.Name, f.ID)
h.apiInit().
Post(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)).
Header("Accept", "application/json").
JSON(fjs).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("module.errors.fieldNameReserved")).
End()
}
func TestModuleCreateWithReservedFieldName(t *testing.T) {
h := newHelper(t)
h.clearModules()
helpers.AllowMe(h, types.NamespaceRbacResource(0), "read", "modules.search")
ns := h.makeNamespace("some-namespace")
helpers.AllowMe(h, types.ModuleRbacResource(0, 0), "update")
fjs := fmt.Sprintf(`{ "name": "foo", "fields": [{ "name": "ownedBy", "kind": "Number" }]}`)
h.apiInit().
Post(fmt.Sprintf("/namespace/%d/module/", ns.ID)).
Header("Accept", "application/json").
JSON(fjs).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("module.errors.fieldNameReserved")).
End()
}
func TestModuleFieldsUpdate_defaults(t *testing.T) {
h := newHelper(t)
h.clearModules()