From 1325b4f27218a336848bc94098a19c09d2957fde Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 16 Sep 2022 18:13:57 +0400 Subject: [PATCH] [#336] session: Support group object sessions Rename `LimitByObject` method of the `session.Object` type to `LimitByObjects` and make it to accept variadic parameter. Signed-off-by: Leonard Lyubich --- go.mod | 2 +- go.sum | 4 +- pool/pool.go | 2 +- session/object.go | 74 +++++++++++++++++++-------------- session/object_test.go | 90 +++++++++++++++++++++++------------------ session/test/session.go | 6 +-- 6 files changed, 99 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index 00f2e23e..b19336ac 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/hrw v1.0.9 github.com/nspcc-dev/neo-go v0.99.2 - github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220919124434-cf868188ef9c + github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20221004142957-5fc2644c680d github.com/nspcc-dev/neofs-contract v0.15.3 github.com/nspcc-dev/tzhash v1.6.1 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index 8168942a..2a15a9ac 100644 --- a/go.sum +++ b/go.sum @@ -263,8 +263,8 @@ github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b h1:J7 github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= -github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220919124434-cf868188ef9c h1:YZwtBY9uypaShbe/NLhosDanIfxt8VhQlSLYUeFIWv8= -github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220919124434-cf868188ef9c/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= +github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20221004142957-5fc2644c680d h1:Oc15A8gDoP/TC5kdJi6TW9AnOp5dYiecZ0tJDRUV7vg= +github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20221004142957-5fc2644c680d/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-contract v0.15.3 h1:7+NwyTtxFAnIevz0hR/XxQf6R2Ej2scjVR2bnnJnhBM= github.com/nspcc-dev/neofs-contract v0.15.3/go.mod h1:BXVZUZUJxrmmDETglXHI8+5DSgn84B9y5DoSWqEjYCs= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= diff --git a/pool/pool.go b/pool/pool.go index c28deb4c..079f05fb 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -1737,7 +1737,7 @@ func (p *Pool) openDefaultSession(ctx *callContext) error { tok.BindContainer(ctx.sessionCnr) if ctx.sessionObjSet { - tok.LimitByObject(ctx.sessionObj) + tok.LimitByObjects(ctx.sessionObj) } // sign the token diff --git a/session/object.go b/session/object.go index 8cd18138..88569515 100644 --- a/session/object.go +++ b/session/object.go @@ -29,8 +29,7 @@ type Object struct { cnrSet bool cnr cid.ID - objSet bool - obj oid.ID + objs []oid.ID } func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error { @@ -39,29 +38,30 @@ func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) er return fmt.Errorf("invalid context %T", c) } - addr := cObj.GetAddress() - if checkFieldPresence && addr == nil { - return errors.New("missing object address") - } - var err error - cnr := addr.GetContainerID() + cnr := cObj.GetContainer() if x.cnrSet = cnr != nil; x.cnrSet { err := x.cnr.ReadFromV2(*cnr) if err != nil { return fmt.Errorf("invalid container ID: %w", err) } } else if checkFieldPresence { - return errors.New("missing container in object address") + return errors.New("missing target container") } - obj := addr.GetObjectID() - if x.objSet = obj != nil; x.objSet { - err = x.obj.ReadFromV2(*obj) - if err != nil { - return fmt.Errorf("invalid object ID: %w", err) + objs := cObj.GetObjects() + if objs != nil { + x.objs = make([]oid.ID, len(objs)) + + for i := range objs { + err = x.objs[i].ReadFromV2(objs[i]) + if err != nil { + return fmt.Errorf("invalid target object: %w", err) + } } + } else { + x.objs = nil } x.verb = ObjectVerb(cObj.GetVerb()) @@ -85,24 +85,25 @@ func (x Object) writeContext() session.TokenContext { var c session.ObjectSessionContext c.SetVerb(session.ObjectSessionVerb(x.verb)) - if x.cnrSet || x.objSet { - var addr refs.Address + if x.cnrSet || len(x.objs) > 0 { + var cnr *refs.ContainerID if x.cnrSet { - var cnr refs.ContainerID - x.cnr.WriteToV2(&cnr) - - addr.SetContainerID(&cnr) + cnr = new(refs.ContainerID) + x.cnr.WriteToV2(cnr) } - if x.objSet { - var obj refs.ObjectID - x.obj.WriteToV2(&obj) + var objs []refs.ObjectID - addr.SetObjectID(&obj) + if x.objs != nil { + objs = make([]refs.ObjectID, len(x.objs)) + + for i := range x.objs { + x.objs[i].WriteToV2(&objs[i]) + } } - c.SetAddress(&addr) + c.SetTarget(cnr, objs...) } return &c @@ -194,22 +195,33 @@ func (x Object) AssertContainer(cnr cid.ID) bool { return x.cnr.Equals(cnr) } -// LimitByObject limits session scope to a given object from the container +// LimitByObjects limits session scope to the given objects from the container // to which Object session is bound. // +// Argument MUST NOT be mutated, make a copy first. +// // See also AssertObject. -func (x *Object) LimitByObject(obj oid.ID) { - x.obj = obj - x.objSet = true +func (x *Object) LimitByObjects(objs ...oid.ID) { + x.objs = objs } // AssertObject checks if Object session is applied to a given object. // // Zero Object is applied to all objects in the container. // -// See also LimitByObject. +// See also LimitByObjects. func (x Object) AssertObject(obj oid.ID) bool { - return !x.objSet || x.obj.Equals(obj) + if len(x.objs) == 0 { + return true + } + + for i := range x.objs { + if x.objs[i].Equals(obj) { + return true + } + } + + return false } // ObjectVerb enumerates object operations. diff --git a/session/object_test.go b/session/object_test.go index c2668508..0b35f374 100644 --- a/session/object_test.go +++ b/session/object_test.go @@ -15,7 +15,6 @@ import ( cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" - oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test" "github.com/nspcc-dev/neofs-sdk-go/session" sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test" @@ -84,15 +83,17 @@ func TestObjectProtocolV2(t *testing.T) { // Context cnr := cidtest.ID() - obj := oidtest.ID() - var addr oid.Address - addr.SetContainer(cnr) - addr.SetObject(obj) - var addrV2 refs.Address - addr.WriteToV2(&addrV2) + obj1 := oidtest.ID() + obj2 := oidtest.ID() + var cnrV2 refs.ContainerID + cnr.WriteToV2(&cnrV2) + var obj1V2 refs.ObjectID + obj1.WriteToV2(&obj1V2) + var obj2V2 refs.ObjectID + obj2.WriteToV2(&obj2V2) var cObj v2session.ObjectSessionContext restoreCtx := func() { - cObj.SetAddress(&addrV2) + cObj.SetTarget(&cnrV2, obj1V2, obj2V2) body.SetContext(&cObj) } restoreCtx() @@ -210,32 +211,29 @@ func TestObjectProtocolV2(t *testing.T) { body.SetContext(nil) }, func() { - cObj.SetAddress(new(refs.Address)) + cObj.SetTarget(nil) }, func() { var brokenCnr refs.ContainerID - brokenCnr.SetValue(append(addrV2.GetContainerID().GetValue(), 1)) - var addr refs.Address - addr.SetContainerID(&brokenCnr) - cObj.SetAddress(&addr) + brokenCnr.SetValue(append(cnrV2.GetValue(), 1)) + cObj.SetTarget(&brokenCnr) }, func() { var brokenObj refs.ObjectID - brokenObj.SetValue(append(addrV2.GetContainerID().GetValue(), 1)) - var addr refs.Address - addr.SetObjectID(&brokenObj) - cObj.SetAddress(&addr) + brokenObj.SetValue(append(obj1V2.GetValue(), 1)) + cObj.SetTarget(&cnrV2, brokenObj) }, }, restore: restoreCtx, assert: func(val session.Object) { require.True(t, val.AssertContainer(cnr)) require.False(t, val.AssertContainer(cidtest.ID())) - require.True(t, val.AssertObject(obj)) + require.True(t, val.AssertObject(obj1)) + require.True(t, val.AssertObject(obj2)) require.False(t, val.AssertObject(oidtest.ID())) }, breakSign: func(m *v2session.Token) { - cnr := m.GetBody().GetContext().(*v2session.ObjectSessionContext).GetAddress().GetContainerID().GetValue() + cnr := m.GetBody().GetContext().(*v2session.ObjectSessionContext).GetContainer().GetValue() cnr[len(cnr)-1]++ }, }, @@ -329,7 +327,8 @@ func TestObject_WriteToV2(t *testing.T) { assert(func(m v2session.Token) { cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Zero(t, cCnr.GetAddress()) + require.Zero(t, cCnr.GetContainer()) + require.Zero(t, cCnr.GetObjects()) }) cnr := cidtest.ID() @@ -337,19 +336,22 @@ func TestObject_WriteToV2(t *testing.T) { var cnrV2 refs.ContainerID cnr.WriteToV2(&cnrV2) - obj := oidtest.ID() + obj1 := oidtest.ID() + obj2 := oidtest.ID() - var objV2 refs.ObjectID - obj.WriteToV2(&objV2) + var obj1V2 refs.ObjectID + obj1.WriteToV2(&obj1V2) + var obj2V2 refs.ObjectID + obj2.WriteToV2(&obj2V2) val.BindContainer(cnr) - val.LimitByObject(obj) + val.LimitByObjects(obj1, obj2) assert(func(m v2session.Token) { cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Equal(t, &cnrV2, cCnr.GetAddress().GetContainerID()) - require.Equal(t, &objV2, cCnr.GetAddress().GetObjectID()) + require.Equal(t, &cnrV2, cCnr.GetContainer()) + require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cCnr.GetObjects()) }) } @@ -361,7 +363,8 @@ func TestObject_BindContainer(t *testing.T) { assertDefaults := func() { cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Zero(t, cCnr.GetAddress()) + require.Zero(t, cCnr.GetContainer()) + require.Zero(t, cCnr.GetObjects()) } assertBinary := func(baseAssert func()) { @@ -401,7 +404,7 @@ func TestObject_BindContainer(t *testing.T) { assertCnr := func() { cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Equal(t, &cnrV2, cObj.GetAddress().GetContainerID()) + require.Equal(t, &cnrV2, cObj.GetContainer()) } assertCnr() @@ -421,7 +424,7 @@ func TestObject_AssertContainer(t *testing.T) { require.True(t, x.AssertContainer(cnr)) } -func TestObject_LimitByObject(t *testing.T) { +func TestObject_LimitByObjects(t *testing.T) { var val session.Object var m v2session.Token filled := sessiontest.Object() @@ -429,7 +432,8 @@ func TestObject_LimitByObject(t *testing.T) { assertDefaults := func() { cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Zero(t, cCnr.GetAddress()) + require.Zero(t, cCnr.GetContainer()) + require.Zero(t, cCnr.GetObjects()) } assertBinary := func(baseAssert func()) { @@ -457,19 +461,22 @@ func TestObject_LimitByObject(t *testing.T) { // set value - obj := oidtest.ID() + obj1 := oidtest.ID() + obj2 := oidtest.ID() - var objV2 refs.ObjectID - obj.WriteToV2(&objV2) + var obj1V2 refs.ObjectID + obj1.WriteToV2(&obj1V2) + var obj2V2 refs.ObjectID + obj2.WriteToV2(&obj2V2) - val.LimitByObject(obj) + val.LimitByObjects(obj1, obj2) val.WriteToV2(&m) assertObj := func() { cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) require.True(t, ok) - require.Equal(t, &objV2, cObj.GetAddress().GetObjectID()) + require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cObj.GetObjects()) } assertObj() @@ -480,16 +487,19 @@ func TestObject_LimitByObject(t *testing.T) { func TestObject_AssertObject(t *testing.T) { var x session.Object - obj := oidtest.ID() + obj1 := oidtest.ID() obj2 := oidtest.ID() + objOther := oidtest.ID() - require.True(t, x.AssertObject(obj)) + require.True(t, x.AssertObject(obj1)) require.True(t, x.AssertObject(obj2)) + require.True(t, x.AssertObject(objOther)) - x.LimitByObject(obj) + x.LimitByObjects(obj1, obj2) - require.True(t, x.AssertObject(obj)) - require.False(t, x.AssertObject(obj2)) + require.True(t, x.AssertObject(obj1)) + require.True(t, x.AssertObject(obj2)) + require.False(t, x.AssertObject(objOther)) } func TestObject_InvalidAt(t *testing.T) { diff --git a/session/test/session.go b/session/test/session.go index fb5a8d8e..95c5d805 100644 --- a/session/test/session.go +++ b/session/test/session.go @@ -71,11 +71,9 @@ func Object() *session.Object { panic(err) } - addr := oidtest.Address() - tok.ForVerb(session.VerbObjectPut) - tok.BindContainer(addr.Container()) - tok.LimitByObject(addr.Object()) + tok.BindContainer(cidtest.ID()) + tok.LimitByObjects(oidtest.ID(), oidtest.ID()) tok.SetID(uuid.New()) tok.SetAuthKey((*neofsecdsa.PublicKey)(&priv.PublicKey)) tok.SetExp(11)