[#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 <ctulhurider@gmail.com>
This commit is contained in:
Leonard Lyubich 2022-09-16 18:13:57 +04:00 committed by LeL
parent c6576c8112
commit 1325b4f272
6 changed files with 99 additions and 79 deletions

2
go.mod
View file

@ -9,7 +9,7 @@ require (
github.com/mr-tron/base58 v1.2.0 github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/hrw v1.0.9 github.com/nspcc-dev/hrw v1.0.9
github.com/nspcc-dev/neo-go v0.99.2 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/neofs-contract v0.15.3
github.com/nspcc-dev/tzhash v1.6.1 github.com/nspcc-dev/tzhash v1.6.1
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0

4
go.sum
View file

@ -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/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.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.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.20221004142957-5fc2644c680d h1:Oc15A8gDoP/TC5kdJi6TW9AnOp5dYiecZ0tJDRUV7vg=
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/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 h1:7+NwyTtxFAnIevz0hR/XxQf6R2Ej2scjVR2bnnJnhBM=
github.com/nspcc-dev/neofs-contract v0.15.3/go.mod h1:BXVZUZUJxrmmDETglXHI8+5DSgn84B9y5DoSWqEjYCs= 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= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=

View file

@ -1737,7 +1737,7 @@ func (p *Pool) openDefaultSession(ctx *callContext) error {
tok.BindContainer(ctx.sessionCnr) tok.BindContainer(ctx.sessionCnr)
if ctx.sessionObjSet { if ctx.sessionObjSet {
tok.LimitByObject(ctx.sessionObj) tok.LimitByObjects(ctx.sessionObj)
} }
// sign the token // sign the token

View file

@ -29,8 +29,7 @@ type Object struct {
cnrSet bool cnrSet bool
cnr cid.ID cnr cid.ID
objSet bool objs []oid.ID
obj oid.ID
} }
func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error { func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error {
@ -39,30 +38,31 @@ func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) er
return fmt.Errorf("invalid context %T", c) return fmt.Errorf("invalid context %T", c)
} }
addr := cObj.GetAddress()
if checkFieldPresence && addr == nil {
return errors.New("missing object address")
}
var err error var err error
cnr := addr.GetContainerID() cnr := cObj.GetContainer()
if x.cnrSet = cnr != nil; x.cnrSet { if x.cnrSet = cnr != nil; x.cnrSet {
err := x.cnr.ReadFromV2(*cnr) err := x.cnr.ReadFromV2(*cnr)
if err != nil { if err != nil {
return fmt.Errorf("invalid container ID: %w", err) return fmt.Errorf("invalid container ID: %w", err)
} }
} else if checkFieldPresence { } else if checkFieldPresence {
return errors.New("missing container in object address") return errors.New("missing target container")
} }
obj := addr.GetObjectID() objs := cObj.GetObjects()
if x.objSet = obj != nil; x.objSet { if objs != nil {
err = x.obj.ReadFromV2(*obj) x.objs = make([]oid.ID, len(objs))
for i := range objs {
err = x.objs[i].ReadFromV2(objs[i])
if err != nil { if err != nil {
return fmt.Errorf("invalid object ID: %w", err) return fmt.Errorf("invalid target object: %w", err)
} }
} }
} else {
x.objs = nil
}
x.verb = ObjectVerb(cObj.GetVerb()) x.verb = ObjectVerb(cObj.GetVerb())
@ -85,24 +85,25 @@ func (x Object) writeContext() session.TokenContext {
var c session.ObjectSessionContext var c session.ObjectSessionContext
c.SetVerb(session.ObjectSessionVerb(x.verb)) c.SetVerb(session.ObjectSessionVerb(x.verb))
if x.cnrSet || x.objSet { if x.cnrSet || len(x.objs) > 0 {
var addr refs.Address var cnr *refs.ContainerID
if x.cnrSet { if x.cnrSet {
var cnr refs.ContainerID cnr = new(refs.ContainerID)
x.cnr.WriteToV2(&cnr) x.cnr.WriteToV2(cnr)
addr.SetContainerID(&cnr)
} }
if x.objSet { var objs []refs.ObjectID
var obj refs.ObjectID
x.obj.WriteToV2(&obj)
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 return &c
@ -194,22 +195,33 @@ func (x Object) AssertContainer(cnr cid.ID) bool {
return x.cnr.Equals(cnr) 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. // to which Object session is bound.
// //
// Argument MUST NOT be mutated, make a copy first.
//
// See also AssertObject. // See also AssertObject.
func (x *Object) LimitByObject(obj oid.ID) { func (x *Object) LimitByObjects(objs ...oid.ID) {
x.obj = obj x.objs = objs
x.objSet = true
} }
// AssertObject checks if Object session is applied to a given object. // AssertObject checks if Object session is applied to a given object.
// //
// Zero Object is applied to all objects in the container. // Zero Object is applied to all objects in the container.
// //
// See also LimitByObject. // See also LimitByObjects.
func (x Object) AssertObject(obj oid.ID) bool { 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. // ObjectVerb enumerates object operations.

View file

@ -15,7 +15,6 @@ import (
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" 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" oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/nspcc-dev/neofs-sdk-go/session" "github.com/nspcc-dev/neofs-sdk-go/session"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test" sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
@ -84,15 +83,17 @@ func TestObjectProtocolV2(t *testing.T) {
// Context // Context
cnr := cidtest.ID() cnr := cidtest.ID()
obj := oidtest.ID() obj1 := oidtest.ID()
var addr oid.Address obj2 := oidtest.ID()
addr.SetContainer(cnr) var cnrV2 refs.ContainerID
addr.SetObject(obj) cnr.WriteToV2(&cnrV2)
var addrV2 refs.Address var obj1V2 refs.ObjectID
addr.WriteToV2(&addrV2) obj1.WriteToV2(&obj1V2)
var obj2V2 refs.ObjectID
obj2.WriteToV2(&obj2V2)
var cObj v2session.ObjectSessionContext var cObj v2session.ObjectSessionContext
restoreCtx := func() { restoreCtx := func() {
cObj.SetAddress(&addrV2) cObj.SetTarget(&cnrV2, obj1V2, obj2V2)
body.SetContext(&cObj) body.SetContext(&cObj)
} }
restoreCtx() restoreCtx()
@ -210,32 +211,29 @@ func TestObjectProtocolV2(t *testing.T) {
body.SetContext(nil) body.SetContext(nil)
}, },
func() { func() {
cObj.SetAddress(new(refs.Address)) cObj.SetTarget(nil)
}, },
func() { func() {
var brokenCnr refs.ContainerID var brokenCnr refs.ContainerID
brokenCnr.SetValue(append(addrV2.GetContainerID().GetValue(), 1)) brokenCnr.SetValue(append(cnrV2.GetValue(), 1))
var addr refs.Address cObj.SetTarget(&brokenCnr)
addr.SetContainerID(&brokenCnr)
cObj.SetAddress(&addr)
}, },
func() { func() {
var brokenObj refs.ObjectID var brokenObj refs.ObjectID
brokenObj.SetValue(append(addrV2.GetContainerID().GetValue(), 1)) brokenObj.SetValue(append(obj1V2.GetValue(), 1))
var addr refs.Address cObj.SetTarget(&cnrV2, brokenObj)
addr.SetObjectID(&brokenObj)
cObj.SetAddress(&addr)
}, },
}, },
restore: restoreCtx, restore: restoreCtx,
assert: func(val session.Object) { assert: func(val session.Object) {
require.True(t, val.AssertContainer(cnr)) require.True(t, val.AssertContainer(cnr))
require.False(t, val.AssertContainer(cidtest.ID())) 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())) require.False(t, val.AssertObject(oidtest.ID()))
}, },
breakSign: func(m *v2session.Token) { 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]++ cnr[len(cnr)-1]++
}, },
}, },
@ -329,7 +327,8 @@ func TestObject_WriteToV2(t *testing.T) {
assert(func(m v2session.Token) { assert(func(m v2session.Token) {
cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Zero(t, cCnr.GetAddress()) require.Zero(t, cCnr.GetContainer())
require.Zero(t, cCnr.GetObjects())
}) })
cnr := cidtest.ID() cnr := cidtest.ID()
@ -337,19 +336,22 @@ func TestObject_WriteToV2(t *testing.T) {
var cnrV2 refs.ContainerID var cnrV2 refs.ContainerID
cnr.WriteToV2(&cnrV2) cnr.WriteToV2(&cnrV2)
obj := oidtest.ID() obj1 := oidtest.ID()
obj2 := oidtest.ID()
var objV2 refs.ObjectID var obj1V2 refs.ObjectID
obj.WriteToV2(&objV2) obj1.WriteToV2(&obj1V2)
var obj2V2 refs.ObjectID
obj2.WriteToV2(&obj2V2)
val.BindContainer(cnr) val.BindContainer(cnr)
val.LimitByObject(obj) val.LimitByObjects(obj1, obj2)
assert(func(m v2session.Token) { assert(func(m v2session.Token) {
cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Equal(t, &cnrV2, cCnr.GetAddress().GetContainerID()) require.Equal(t, &cnrV2, cCnr.GetContainer())
require.Equal(t, &objV2, cCnr.GetAddress().GetObjectID()) require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cCnr.GetObjects())
}) })
} }
@ -361,7 +363,8 @@ func TestObject_BindContainer(t *testing.T) {
assertDefaults := func() { assertDefaults := func() {
cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Zero(t, cCnr.GetAddress()) require.Zero(t, cCnr.GetContainer())
require.Zero(t, cCnr.GetObjects())
} }
assertBinary := func(baseAssert func()) { assertBinary := func(baseAssert func()) {
@ -401,7 +404,7 @@ func TestObject_BindContainer(t *testing.T) {
assertCnr := func() { assertCnr := func() {
cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Equal(t, &cnrV2, cObj.GetAddress().GetContainerID()) require.Equal(t, &cnrV2, cObj.GetContainer())
} }
assertCnr() assertCnr()
@ -421,7 +424,7 @@ func TestObject_AssertContainer(t *testing.T) {
require.True(t, x.AssertContainer(cnr)) require.True(t, x.AssertContainer(cnr))
} }
func TestObject_LimitByObject(t *testing.T) { func TestObject_LimitByObjects(t *testing.T) {
var val session.Object var val session.Object
var m v2session.Token var m v2session.Token
filled := sessiontest.Object() filled := sessiontest.Object()
@ -429,7 +432,8 @@ func TestObject_LimitByObject(t *testing.T) {
assertDefaults := func() { assertDefaults := func() {
cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cCnr, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Zero(t, cCnr.GetAddress()) require.Zero(t, cCnr.GetContainer())
require.Zero(t, cCnr.GetObjects())
} }
assertBinary := func(baseAssert func()) { assertBinary := func(baseAssert func()) {
@ -457,19 +461,22 @@ func TestObject_LimitByObject(t *testing.T) {
// set value // set value
obj := oidtest.ID() obj1 := oidtest.ID()
obj2 := oidtest.ID()
var objV2 refs.ObjectID var obj1V2 refs.ObjectID
obj.WriteToV2(&objV2) obj1.WriteToV2(&obj1V2)
var obj2V2 refs.ObjectID
obj2.WriteToV2(&obj2V2)
val.LimitByObject(obj) val.LimitByObjects(obj1, obj2)
val.WriteToV2(&m) val.WriteToV2(&m)
assertObj := func() { assertObj := func() {
cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext) cObj, ok := m.GetBody().GetContext().(*v2session.ObjectSessionContext)
require.True(t, ok) require.True(t, ok)
require.Equal(t, &objV2, cObj.GetAddress().GetObjectID()) require.Equal(t, []refs.ObjectID{obj1V2, obj2V2}, cObj.GetObjects())
} }
assertObj() assertObj()
@ -480,16 +487,19 @@ func TestObject_LimitByObject(t *testing.T) {
func TestObject_AssertObject(t *testing.T) { func TestObject_AssertObject(t *testing.T) {
var x session.Object var x session.Object
obj := oidtest.ID() obj1 := oidtest.ID()
obj2 := 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(obj2))
require.True(t, x.AssertObject(objOther))
x.LimitByObject(obj) x.LimitByObjects(obj1, obj2)
require.True(t, x.AssertObject(obj)) require.True(t, x.AssertObject(obj1))
require.False(t, x.AssertObject(obj2)) require.True(t, x.AssertObject(obj2))
require.False(t, x.AssertObject(objOther))
} }
func TestObject_InvalidAt(t *testing.T) { func TestObject_InvalidAt(t *testing.T) {

View file

@ -71,11 +71,9 @@ func Object() *session.Object {
panic(err) panic(err)
} }
addr := oidtest.Address()
tok.ForVerb(session.VerbObjectPut) tok.ForVerb(session.VerbObjectPut)
tok.BindContainer(addr.Container()) tok.BindContainer(cidtest.ID())
tok.LimitByObject(addr.Object()) tok.LimitByObjects(oidtest.ID(), oidtest.ID())
tok.SetID(uuid.New()) tok.SetID(uuid.New())
tok.SetAuthKey((*neofsecdsa.PublicKey)(&priv.PublicKey)) tok.SetAuthKey((*neofsecdsa.PublicKey)(&priv.PublicKey))
tok.SetExp(11) tok.SetExp(11)