From 01dd17e30ac05ea4f3d9171659f8916fd0d0ecf0 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 23 Jun 2021 16:30:14 +0300 Subject: [PATCH] [#633] object: Prevent duplicate attributes by key Keys of object attributes must be unique according to NeoFS specification. Make `FormatValidator.Validate` method to return an error if at least one attribute is duplicated. Signed-off-by: Leonard Lyubich --- pkg/core/object/fmt.go | 24 ++++++++++++++++++++++++ pkg/core/object/fmt_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pkg/core/object/fmt.go b/pkg/core/object/fmt.go index e12aaed56..40e07e748 100644 --- a/pkg/core/object/fmt.go +++ b/pkg/core/object/fmt.go @@ -77,6 +77,10 @@ func (v *FormatValidator) Validate(obj *Object) error { } for ; obj != nil; obj = obj.GetParent() { + if err := v.checkAttributes(obj); err != nil { + return fmt.Errorf("invalid attributes: %w", err) + } + if err := v.validateSignatureKey(obj); err != nil { return fmt.Errorf("(%T) could not validate signature key: %w", v, err) } @@ -227,6 +231,26 @@ func expirationEpochAttribute(obj *Object) (uint64, error) { return 0, errNoExpirationEpoch } +var errDuplAttr = errors.New("duplication of attributes detected") + +func (v *FormatValidator) checkAttributes(obj *Object) error { + as := obj.Attributes() + + mUnique := make(map[string]struct{}, len(as)) + + for _, a := range as { + key := a.Key() + + if _, was := mUnique[key]; was { + return errDuplAttr + } + + mUnique[key] = struct{}{} + } + + return nil +} + // WithNetState returns options to set network state interface. // // FIXME: network state is a required parameter. diff --git a/pkg/core/object/fmt_test.go b/pkg/core/object/fmt_test.go index 0fbb4ce5b..c23ee28b8 100644 --- a/pkg/core/object/fmt_test.go +++ b/pkg/core/object/fmt_test.go @@ -219,4 +219,28 @@ func TestFormatValidator_Validate(t *testing.T) { require.NoError(t, err) }) }) + + t.Run("attributes", func(t *testing.T) { + t.Run("duplication", func(t *testing.T) { + obj := blankValidObject(t, ownerKey) + + a1 := object.NewAttribute() + a1.SetKey("key1") + a1.SetValue("val1") + + a2 := object.NewAttribute() + a2.SetKey("key2") + a2.SetValue("val2") + + obj.SetAttributes(a1, a2) + + err := v.checkAttributes(obj.Object()) + require.NoError(t, err) + + a2.SetKey(a1.Key()) + + err = v.checkAttributes(obj.Object()) + require.Equal(t, errDuplAttr, err) + }) + }) }