forked from TrueCloudLab/frostfs-api-go
Merge pull request #78 from nspcc-dev/request-signed-payload
Implement SignedDataSource on all request messages
This commit is contained in:
commit
18bd5011f1
23 changed files with 1516 additions and 71 deletions
167
accounting/sign.go
Normal file
167
accounting/sign.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package accounting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m BalanceRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m BalanceRequest) SignedDataSize() int {
|
||||||
|
return m.GetOwnerID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m BalanceRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
sz := m.SignedDataSize()
|
||||||
|
if len(p) < sz {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(p, m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
return sz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m GetRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m GetRequest) SignedDataSize() int {
|
||||||
|
return m.GetID().Size() + m.GetOwnerID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m GetRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
sz := m.SignedDataSize()
|
||||||
|
if len(p) < sz {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetID().Bytes())
|
||||||
|
|
||||||
|
copy(p[off:], m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
return sz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m PutRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m PutRequest) SignedDataSize() (sz int) {
|
||||||
|
sz += m.GetOwnerID().Size()
|
||||||
|
|
||||||
|
sz += m.GetMessageID().Size()
|
||||||
|
|
||||||
|
sz += 8
|
||||||
|
|
||||||
|
if amount := m.GetAmount(); amount != nil {
|
||||||
|
sz += amount.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m PutRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetMessageID().Bytes())
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(p[off:], m.GetHeight())
|
||||||
|
off += 8
|
||||||
|
|
||||||
|
if amount := m.GetAmount(); amount != nil {
|
||||||
|
n, err := amount.MarshalTo(p[off:])
|
||||||
|
off += n
|
||||||
|
if err != nil {
|
||||||
|
return off + n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m ListRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m ListRequest) SignedDataSize() int {
|
||||||
|
return m.GetOwnerID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m ListRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
sz := m.SignedDataSize()
|
||||||
|
if len(p) < sz {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(p, m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
return sz, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m DeleteRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m DeleteRequest) SignedDataSize() (sz int) {
|
||||||
|
sz += m.GetID().Size()
|
||||||
|
|
||||||
|
sz += m.GetOwnerID().Size()
|
||||||
|
|
||||||
|
sz += m.GetMessageID().Size()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m DeleteRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetID().Bytes())
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetMessageID().Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
185
accounting/sign_test.go
Normal file
185
accounting/sign_test.go
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
package accounting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/decimal"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
"github.com/nspcc-dev/neofs-crypto/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignBalanceRequest(t *testing.T) {
|
||||||
|
sk := test.DecodeKey(0)
|
||||||
|
|
||||||
|
type sigType interface {
|
||||||
|
service.SignedDataWithToken
|
||||||
|
service.SignKeyPairAccumulator
|
||||||
|
service.SignKeyPairSource
|
||||||
|
SetToken(*service.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []struct {
|
||||||
|
constructor func() sigType
|
||||||
|
payloadCorrupt []func(sigType)
|
||||||
|
}{
|
||||||
|
{ // BalanceRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(BalanceRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*BalanceRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // GetRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(GetRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*GetRequest)
|
||||||
|
|
||||||
|
id, err := NewChequeID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req.SetID(id)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*GetRequest)
|
||||||
|
|
||||||
|
id := req.GetOwnerID()
|
||||||
|
id[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // PutRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
req := new(PutRequest)
|
||||||
|
|
||||||
|
amount := decimal.New(1)
|
||||||
|
req.SetAmount(amount)
|
||||||
|
|
||||||
|
return req
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
mid := req.GetMessageID()
|
||||||
|
mid[0]++
|
||||||
|
|
||||||
|
req.SetMessageID(mid)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
req.SetHeight(req.GetHeight() + 1)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
amount := req.GetAmount()
|
||||||
|
if amount == nil {
|
||||||
|
req.SetAmount(decimal.New(0))
|
||||||
|
} else {
|
||||||
|
req.SetAmount(amount.Add(decimal.New(amount.GetValue())))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // ListRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(ListRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*ListRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(DeleteRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*DeleteRequest)
|
||||||
|
|
||||||
|
id, err := NewChequeID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req.SetID(id)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*DeleteRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*DeleteRequest)
|
||||||
|
|
||||||
|
mid := req.GetMessageID()
|
||||||
|
mid[0]++
|
||||||
|
|
||||||
|
req.SetMessageID(mid)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
{ // token corruptions
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
token := new(service.Token)
|
||||||
|
v.SetToken(token)
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
token.SetSessionKey(append(token.GetSessionKey(), 1))
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // payload corruptions
|
||||||
|
for _, corruption := range item.payloadCorrupt {
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
corruption(v)
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -351,3 +351,103 @@ func (m *Settlement) Equal(s *Settlement) bool {
|
||||||
}
|
}
|
||||||
return len(m.Transactions) == 0 || reflect.DeepEqual(m.Transactions, s.Transactions)
|
return len(m.Transactions) == 0 || reflect.DeepEqual(m.Transactions, s.Transactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m BalanceRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *BalanceRequest) SetOwnerID(owner OwnerID) {
|
||||||
|
m.OwnerID = owner
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetID is an ID field getter.
|
||||||
|
func (m GetRequest) GetID() ChequeID {
|
||||||
|
return m.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetID is an ID field setter.
|
||||||
|
func (m *GetRequest) SetID(id ChequeID) {
|
||||||
|
m.ID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m GetRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *GetRequest) SetOwnerID(id OwnerID) {
|
||||||
|
m.OwnerID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m PutRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *PutRequest) SetOwnerID(id OwnerID) {
|
||||||
|
m.OwnerID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageID is a MessageID field getter.
|
||||||
|
func (m PutRequest) GetMessageID() MessageID {
|
||||||
|
return m.MessageID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMessageID is a MessageID field setter.
|
||||||
|
func (m *PutRequest) SetMessageID(id MessageID) {
|
||||||
|
m.MessageID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAmount is an Amount field setter.
|
||||||
|
func (m *PutRequest) SetAmount(amount *decimal.Decimal) {
|
||||||
|
m.Amount = amount
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHeight is a Height field setter.
|
||||||
|
func (m *PutRequest) SetHeight(h uint64) {
|
||||||
|
m.Height = h
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m ListRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *ListRequest) SetOwnerID(id OwnerID) {
|
||||||
|
m.OwnerID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetID is an ID field getter.
|
||||||
|
func (m DeleteRequest) GetID() ChequeID {
|
||||||
|
return m.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetID is an ID field setter.
|
||||||
|
func (m *DeleteRequest) SetID(id ChequeID) {
|
||||||
|
m.ID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m DeleteRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *DeleteRequest) SetOwnerID(id OwnerID) {
|
||||||
|
m.OwnerID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageID is a MessageID field getter.
|
||||||
|
func (m DeleteRequest) GetMessageID() MessageID {
|
||||||
|
return m.MessageID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMessageID is a MessageID field setter.
|
||||||
|
func (m *DeleteRequest) SetMessageID(id MessageID) {
|
||||||
|
m.MessageID = id
|
||||||
|
}
|
||||||
|
|
|
@ -84,3 +84,110 @@ func TestCheque(t *testing.T) {
|
||||||
require.Equal(t, cheque.Amount, decimal.NewGAS(42))
|
require.Equal(t, cheque.Amount, decimal.NewGAS(42))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBalanceRequest_SetOwnerID(t *testing.T) {
|
||||||
|
ownerID := OwnerID{1, 2, 3}
|
||||||
|
m := new(BalanceRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(ownerID)
|
||||||
|
|
||||||
|
require.Equal(t, ownerID, m.GetOwnerID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("id", func(t *testing.T) {
|
||||||
|
id := ChequeID("test id")
|
||||||
|
m := new(GetRequest)
|
||||||
|
|
||||||
|
m.SetID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("owner", func(t *testing.T) {
|
||||||
|
id := OwnerID{1, 2, 3}
|
||||||
|
m := new(GetRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetOwnerID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("owner", func(t *testing.T) {
|
||||||
|
id := OwnerID{1, 2, 3}
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetOwnerID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("message ID", func(t *testing.T) {
|
||||||
|
id, err := refs.NewUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m := new(PutRequest)
|
||||||
|
m.SetMessageID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetMessageID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("amount", func(t *testing.T) {
|
||||||
|
amount := decimal.New(1)
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetAmount(amount)
|
||||||
|
|
||||||
|
require.Equal(t, amount, m.GetAmount())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("height", func(t *testing.T) {
|
||||||
|
h := uint64(3)
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetHeight(h)
|
||||||
|
|
||||||
|
require.Equal(t, h, m.GetHeight())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListRequestGettersSetters(t *testing.T) {
|
||||||
|
ownerID := OwnerID{1, 2, 3}
|
||||||
|
m := new(ListRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(ownerID)
|
||||||
|
|
||||||
|
require.Equal(t, ownerID, m.GetOwnerID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("id", func(t *testing.T) {
|
||||||
|
id := ChequeID("test id")
|
||||||
|
m := new(DeleteRequest)
|
||||||
|
|
||||||
|
m.SetID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("owner", func(t *testing.T) {
|
||||||
|
id := OwnerID{1, 2, 3}
|
||||||
|
m := new(DeleteRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetOwnerID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("message ID", func(t *testing.T) {
|
||||||
|
id, err := refs.NewUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m := new(DeleteRequest)
|
||||||
|
m.SetMessageID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetMessageID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
46
bootstrap/sign.go
Normal file
46
bootstrap/sign.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m Request) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m Request) SignedDataSize() (sz int) {
|
||||||
|
sz += m.GetType().Size()
|
||||||
|
|
||||||
|
sz += m.GetState().Size()
|
||||||
|
|
||||||
|
info := m.GetInfo()
|
||||||
|
sz += info.Size()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m Request) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetType().Bytes())
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetState().Bytes())
|
||||||
|
|
||||||
|
info := m.GetInfo()
|
||||||
|
// FIXME: implement and use stable functions
|
||||||
|
n, err := info.MarshalTo(p[off:])
|
||||||
|
off += n
|
||||||
|
|
||||||
|
return off, err
|
||||||
|
}
|
82
bootstrap/sign_test.go
Normal file
82
bootstrap/sign_test.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
"github.com/nspcc-dev/neofs-crypto/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequestSign(t *testing.T) {
|
||||||
|
sk := test.DecodeKey(0)
|
||||||
|
|
||||||
|
type sigType interface {
|
||||||
|
service.SignedDataWithToken
|
||||||
|
service.SignKeyPairAccumulator
|
||||||
|
service.SignKeyPairSource
|
||||||
|
SetToken(*service.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []struct {
|
||||||
|
constructor func() sigType
|
||||||
|
payloadCorrupt []func(sigType)
|
||||||
|
}{
|
||||||
|
{ // Request
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(Request)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*Request)
|
||||||
|
|
||||||
|
req.SetType(req.GetType() + 1)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*Request)
|
||||||
|
|
||||||
|
req.SetState(req.GetState() + 1)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*Request)
|
||||||
|
|
||||||
|
info := req.GetInfo()
|
||||||
|
info.Address += "1"
|
||||||
|
|
||||||
|
req.SetInfo(info)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
{ // token corruptions
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
token := new(service.Token)
|
||||||
|
v.SetToken(token)
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
token.SetSessionKey(append(token.GetSessionKey(), 1))
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // payload corruptions
|
||||||
|
for _, corruption := range item.payloadCorrupt {
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
corruption(v)
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package bootstrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -27,6 +28,8 @@ var (
|
||||||
_ proto.Message = (*SpreadMap)(nil)
|
_ proto.Message = (*SpreadMap)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var requestEndianness = binary.BigEndian
|
||||||
|
|
||||||
// Equals checks whether two NodeInfo has same address.
|
// Equals checks whether two NodeInfo has same address.
|
||||||
func (m NodeInfo) Equals(n1 NodeInfo) bool {
|
func (m NodeInfo) Equals(n1 NodeInfo) bool {
|
||||||
return m.Address == n1.Address && bytes.Equal(m.PubKey, n1.PubKey)
|
return m.Address == n1.Address && bytes.Equal(m.PubKey, n1.PubKey)
|
||||||
|
@ -98,3 +101,37 @@ func (m SpreadMap) String() string {
|
||||||
", " +
|
", " +
|
||||||
"Netmap: [" + strings.Join(result, ",") + "]>"
|
"Netmap: [" + strings.Join(result, ",") + "]>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetType is a Type field getter.
|
||||||
|
func (m Request) GetType() NodeType {
|
||||||
|
return m.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetType is a Type field setter.
|
||||||
|
func (m *Request) SetType(t NodeType) {
|
||||||
|
m.Type = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetState is a State field setter.
|
||||||
|
func (m *Request) SetState(state Request_State) {
|
||||||
|
m.State = state
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInfo is an Info field getter.
|
||||||
|
func (m *Request) SetInfo(info NodeInfo) {
|
||||||
|
m.Info = info
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size necessary for a binary representation of the state.
|
||||||
|
func (x Request_State) Size() int {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns a binary representation of the state.
|
||||||
|
func (x Request_State) Bytes() []byte {
|
||||||
|
data := make([]byte, x.Size())
|
||||||
|
|
||||||
|
requestEndianness.PutUint32(data, uint32(x))
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
39
bootstrap/types_test.go
Normal file
39
bootstrap/types_test.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package bootstrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("type", func(t *testing.T) {
|
||||||
|
rt := NodeType(1)
|
||||||
|
m := new(Request)
|
||||||
|
|
||||||
|
m.SetType(rt)
|
||||||
|
|
||||||
|
require.Equal(t, rt, m.GetType())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("state", func(t *testing.T) {
|
||||||
|
st := Request_State(1)
|
||||||
|
m := new(Request)
|
||||||
|
|
||||||
|
m.SetState(st)
|
||||||
|
|
||||||
|
require.Equal(t, st, m.GetState())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("info", func(t *testing.T) {
|
||||||
|
info := NodeInfo{
|
||||||
|
Address: "some address",
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(Request)
|
||||||
|
|
||||||
|
m.SetInfo(info)
|
||||||
|
|
||||||
|
require.Equal(t, info, m.GetInfo())
|
||||||
|
})
|
||||||
|
}
|
137
container/sign.go
Normal file
137
container/sign.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
service "github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
var requestEndianness = binary.BigEndian
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m PutRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m PutRequest) SignedDataSize() (sz int) {
|
||||||
|
sz += m.GetMessageID().Size()
|
||||||
|
|
||||||
|
sz += 8
|
||||||
|
|
||||||
|
sz += m.GetOwnerID().Size()
|
||||||
|
|
||||||
|
rules := m.GetRules()
|
||||||
|
sz += rules.Size()
|
||||||
|
|
||||||
|
sz += 4
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m PutRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetMessageID().Bytes())
|
||||||
|
|
||||||
|
requestEndianness.PutUint64(p[off:], m.GetCapacity())
|
||||||
|
off += 8
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
rules := m.GetRules()
|
||||||
|
// FIXME: implement and use stable functions
|
||||||
|
n, err := rules.MarshalTo(p[off:])
|
||||||
|
off += n
|
||||||
|
if err != nil {
|
||||||
|
return off, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestEndianness.PutUint32(p[off:], m.GetBasicACL())
|
||||||
|
off += 4
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m DeleteRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m DeleteRequest) SignedDataSize() int {
|
||||||
|
return m.GetCID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m DeleteRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetCID().Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m GetRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m GetRequest) SignedDataSize() int {
|
||||||
|
return m.GetCID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m GetRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetCID().Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m ListRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m ListRequest) SignedDataSize() int {
|
||||||
|
return m.GetOwnerID().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m ListRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetOwnerID().Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
143
container/sign_test.go
Normal file
143
container/sign_test.go
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
"github.com/nspcc-dev/neofs-crypto/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequestSign(t *testing.T) {
|
||||||
|
sk := test.DecodeKey(0)
|
||||||
|
|
||||||
|
type sigType interface {
|
||||||
|
service.SignedDataWithToken
|
||||||
|
service.SignKeyPairAccumulator
|
||||||
|
service.SignKeyPairSource
|
||||||
|
SetToken(*service.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []struct {
|
||||||
|
constructor func() sigType
|
||||||
|
payloadCorrupt []func(sigType)
|
||||||
|
}{
|
||||||
|
{ // PutRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(PutRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
id := req.GetMessageID()
|
||||||
|
id[0]++
|
||||||
|
|
||||||
|
req.SetMessageID(id)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
req.SetCapacity(req.GetCapacity() + 1)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
rules := req.GetRules()
|
||||||
|
rules.ReplFactor++
|
||||||
|
|
||||||
|
req.SetRules(rules)
|
||||||
|
},
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*PutRequest)
|
||||||
|
|
||||||
|
req.SetBasicACL(req.GetBasicACL() + 1)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // DeleteRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(DeleteRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*DeleteRequest)
|
||||||
|
|
||||||
|
cid := req.GetCID()
|
||||||
|
cid[0]++
|
||||||
|
|
||||||
|
req.SetCID(cid)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // GetRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(GetRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*GetRequest)
|
||||||
|
|
||||||
|
cid := req.GetCID()
|
||||||
|
cid[0]++
|
||||||
|
|
||||||
|
req.SetCID(cid)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // ListRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(ListRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*ListRequest)
|
||||||
|
|
||||||
|
owner := req.GetOwnerID()
|
||||||
|
owner[0]++
|
||||||
|
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
{ // token corruptions
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
token := new(service.Token)
|
||||||
|
v.SetToken(token)
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
token.SetSessionKey(append(token.GetSessionKey(), 1))
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // payload corruptions
|
||||||
|
for _, corruption := range item.payloadCorrupt {
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
corruption(v)
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -93,3 +93,68 @@ func NewTestContainer() (*Container, error) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMessageID is a MessageID field getter.
|
||||||
|
func (m PutRequest) GetMessageID() MessageID {
|
||||||
|
return m.MessageID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMessageID is a MessageID field getter.
|
||||||
|
func (m *PutRequest) SetMessageID(id MessageID) {
|
||||||
|
m.MessageID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCapacity is a Capacity field setter.
|
||||||
|
func (m *PutRequest) SetCapacity(c uint64) {
|
||||||
|
m.Capacity = c
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m PutRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *PutRequest) SetOwnerID(owner OwnerID) {
|
||||||
|
m.OwnerID = owner
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRules is a Rules field setter.
|
||||||
|
func (m *PutRequest) SetRules(rules netmap.PlacementRule) {
|
||||||
|
m.Rules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBasicACL is a BasicACL field setter.
|
||||||
|
func (m *PutRequest) SetBasicACL(acl uint32) {
|
||||||
|
m.BasicACL = acl
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCID is a CID field getter.
|
||||||
|
func (m DeleteRequest) GetCID() CID {
|
||||||
|
return m.CID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCID is a CID field setter.
|
||||||
|
func (m *DeleteRequest) SetCID(cid CID) {
|
||||||
|
m.CID = cid
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCID is a CID field getter.
|
||||||
|
func (m GetRequest) GetCID() CID {
|
||||||
|
return m.CID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCID is a CID field setter.
|
||||||
|
func (m *GetRequest) SetCID(cid CID) {
|
||||||
|
m.CID = cid
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOwnerID is an OwnerID field getter.
|
||||||
|
func (m ListRequest) GetOwnerID() OwnerID {
|
||||||
|
return m.OwnerID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOwnerID is an OwnerID field setter.
|
||||||
|
func (m *ListRequest) SetOwnerID(owner OwnerID) {
|
||||||
|
m.OwnerID = owner
|
||||||
|
}
|
||||||
|
|
|
@ -55,3 +55,88 @@ func TestCID(t *testing.T) {
|
||||||
require.Equal(t, cid1, cid2)
|
require.Equal(t, cid1, cid2)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPutRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("owner", func(t *testing.T) {
|
||||||
|
owner := OwnerID{1, 2, 3}
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(owner)
|
||||||
|
|
||||||
|
require.Equal(t, owner, m.GetOwnerID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("capacity", func(t *testing.T) {
|
||||||
|
cp := uint64(3)
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetCapacity(cp)
|
||||||
|
|
||||||
|
require.Equal(t, cp, m.GetCapacity())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("message ID", func(t *testing.T) {
|
||||||
|
id, err := refs.NewUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetMessageID(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, m.GetMessageID())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rules", func(t *testing.T) {
|
||||||
|
rules := netmap.PlacementRule{
|
||||||
|
ReplFactor: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetRules(rules)
|
||||||
|
|
||||||
|
require.Equal(t, rules, m.GetRules())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("basic ACL", func(t *testing.T) {
|
||||||
|
bACL := uint32(5)
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetBasicACL(bACL)
|
||||||
|
|
||||||
|
require.Equal(t, bACL, m.GetBasicACL())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("cid", func(t *testing.T) {
|
||||||
|
cid := CID{1, 2, 3}
|
||||||
|
m := new(DeleteRequest)
|
||||||
|
|
||||||
|
m.SetCID(cid)
|
||||||
|
|
||||||
|
require.Equal(t, cid, m.GetCID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("cid", func(t *testing.T) {
|
||||||
|
cid := CID{1, 2, 3}
|
||||||
|
m := new(GetRequest)
|
||||||
|
|
||||||
|
m.SetCID(cid)
|
||||||
|
|
||||||
|
require.Equal(t, cid, m.GetCID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("owner", func(t *testing.T) {
|
||||||
|
owner := OwnerID{1, 2, 3}
|
||||||
|
m := new(PutRequest)
|
||||||
|
|
||||||
|
m.SetOwnerID(owner)
|
||||||
|
|
||||||
|
require.Equal(t, owner, m.GetOwnerID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
103
object/sign.go
103
object/sign.go
|
@ -3,34 +3,27 @@ package object
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
//
|
//
|
||||||
// If payload is nil, ErrHeaderNotFound returns.
|
// If payload is nil, ErrHeaderNotFound returns.
|
||||||
func (m PutRequest) SignedData() ([]byte, error) {
|
func (m PutRequest) SignedData() ([]byte, error) {
|
||||||
sz := m.SignedDataSize()
|
return service.SignedDataFromReader(m)
|
||||||
if sz < 0 {
|
|
||||||
return nil, ErrHeaderNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make([]byte, sz)
|
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m PutRequest) ReadSignedData(p []byte) error {
|
func (m PutRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
r := m.GetR()
|
r := m.GetR()
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return ErrHeaderNotFound
|
return 0, ErrHeaderNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := r.MarshalTo(p)
|
return r.MarshalTo(p)
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns the size of payload of the Put request.
|
// SignedDataSize returns the size of payload of the Put request.
|
||||||
|
@ -47,26 +40,26 @@ func (m PutRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m GetRequest) SignedData() ([]byte, error) {
|
func (m GetRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m GetRequest) ReadSignedData(p []byte) error {
|
func (m GetRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
addr := m.GetAddress()
|
addr := m.GetAddress()
|
||||||
|
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
off := copy(p, addr.CID.Bytes())
|
var off int
|
||||||
|
|
||||||
copy(p[off:], addr.ObjectID.Bytes())
|
off += copy(p[off:], addr.CID.Bytes())
|
||||||
|
|
||||||
return nil
|
off += copy(p[off:], addr.ObjectID.Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
@ -76,28 +69,28 @@ func (m GetRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m HeadRequest) SignedData() ([]byte, error) {
|
func (m HeadRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m HeadRequest) ReadSignedData(p []byte) error {
|
func (m HeadRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.GetFullHeaders() {
|
if m.GetFullHeaders() {
|
||||||
p[0] = 1
|
p[0] = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
off := 1 + copy(p[1:], m.Address.CID.Bytes())
|
off := 1
|
||||||
|
|
||||||
copy(p[off:], m.Address.ObjectID.Bytes())
|
off += copy(p[off:], m.Address.CID.Bytes())
|
||||||
|
|
||||||
return nil
|
off += copy(p[off:], m.Address.ObjectID.Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
@ -107,24 +100,24 @@ func (m HeadRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m DeleteRequest) SignedData() ([]byte, error) {
|
func (m DeleteRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m DeleteRequest) ReadSignedData(p []byte) error {
|
func (m DeleteRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
off := copy(p, m.OwnerID.Bytes())
|
var off int
|
||||||
|
|
||||||
copy(p[off:], addressBytes(m.Address))
|
off += copy(p[off:], m.OwnerID.Bytes())
|
||||||
|
|
||||||
return nil
|
off += copy(p[off:], addressBytes(m.Address))
|
||||||
|
|
||||||
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
@ -134,27 +127,25 @@ func (m DeleteRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m GetRangeRequest) SignedData() ([]byte, error) {
|
func (m GetRangeRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m GetRangeRequest) ReadSignedData(p []byte) error {
|
func (m GetRangeRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := (&m.Range).MarshalTo(p)
|
n, err := (&m.Range).MarshalTo(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(p[n:], addressBytes(m.GetAddress()))
|
n += copy(p[n:], addressBytes(m.GetAddress()))
|
||||||
|
|
||||||
return nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
@ -164,17 +155,15 @@ func (m GetRangeRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m GetRangeHashRequest) SignedData() ([]byte, error) {
|
func (m GetRangeHashRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m GetRangeHashRequest) ReadSignedData(p []byte) error {
|
func (m GetRangeHashRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
var off int
|
var off int
|
||||||
|
@ -185,7 +174,7 @@ func (m GetRangeHashRequest) ReadSignedData(p []byte) error {
|
||||||
|
|
||||||
off += copy(p[off:], m.GetSalt())
|
off += copy(p[off:], m.GetSalt())
|
||||||
|
|
||||||
return nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
@ -203,17 +192,15 @@ func (m GetRangeHashRequest) SignedDataSize() int {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m SearchRequest) SignedData() ([]byte, error) {
|
func (m SearchRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
return data, m.ReadSignedData(data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies payload bytes to passed buffer.
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
//
|
//
|
||||||
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
// If the buffer size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
func (m SearchRequest) ReadSignedData(p []byte) error {
|
func (m SearchRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
if len(p) < m.SignedDataSize() {
|
if len(p) < m.SignedDataSize() {
|
||||||
return io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
var off int
|
var off int
|
||||||
|
@ -223,9 +210,9 @@ func (m SearchRequest) ReadSignedData(p []byte) error {
|
||||||
binary.BigEndian.PutUint32(p[off:], m.GetQueryVersion())
|
binary.BigEndian.PutUint32(p[off:], m.GetQueryVersion())
|
||||||
off += 4
|
off += 4
|
||||||
|
|
||||||
copy(p[off:], m.GetQuery())
|
off += copy(p[off:], m.GetQuery())
|
||||||
|
|
||||||
return nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
|
|
@ -43,3 +43,7 @@ const ErrNilDataWithTokenSignAccumulator = internal.Error("signed data with toke
|
||||||
// ErrNilSignatureKeySourceWithToken is returned by functions that expect
|
// ErrNilSignatureKeySourceWithToken is returned by functions that expect
|
||||||
// a non-nil SignatureKeySourceWithToken, but received nil.
|
// a non-nil SignatureKeySourceWithToken, but received nil.
|
||||||
const ErrNilSignatureKeySourceWithToken = internal.Error("key-signature source with token is nil")
|
const ErrNilSignatureKeySourceWithToken = internal.Error("key-signature source with token is nil")
|
||||||
|
|
||||||
|
// ErrNilSignedDataReader is returned by functions that expect
|
||||||
|
// a non-nil SignedDataReader, but received nil.
|
||||||
|
const ErrNilSignedDataReader = internal.Error("signed data reader is nil")
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ NodeRole = iota
|
_ NodeRole = iota
|
||||||
// InnerRingNode that work like IR node.
|
// InnerRingNode that work like IR node.
|
||||||
|
@ -19,3 +21,17 @@ func (nt NodeRole) String() string {
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size returns the size necessary for a binary representation of the NodeRole.
|
||||||
|
func (nt NodeRole) Size() int {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns a binary representation of the NodeRole.
|
||||||
|
func (nt NodeRole) Bytes() []byte {
|
||||||
|
data := make([]byte, nt.Size())
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(data, uint32(nt))
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
|
@ -123,11 +123,7 @@ func (m *Token) AddSignKey(sig []byte, _ *ecdsa.PublicKey) {
|
||||||
|
|
||||||
// SignedData returns token information in a binary representation.
|
// SignedData returns token information in a binary representation.
|
||||||
func (m *Token) SignedData() ([]byte, error) {
|
func (m *Token) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return SignedDataFromReader(m)
|
||||||
|
|
||||||
copyTokenSignedData(data, m)
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadSignedData copies a binary representation of the token information to passed buffer.
|
// ReadSignedData copies a binary representation of the token information to passed buffer.
|
||||||
|
|
18
service/utils.go
Normal file
18
service/utils.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
// SignedDataFromReader allocates buffer and reads bytes from passed reader to it.
|
||||||
|
//
|
||||||
|
// If passed SignedDataReader is nil, ErrNilSignedDataReader returns.
|
||||||
|
func SignedDataFromReader(r SignedDataReader) ([]byte, error) {
|
||||||
|
if r == nil {
|
||||||
|
return nil, ErrNilSignedDataReader
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, r.SignedDataSize())
|
||||||
|
|
||||||
|
if _, err := r.ReadSignedData(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
34
service/utils_test.go
Normal file
34
service/utils_test.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSignedDataFromReader(t *testing.T) {
|
||||||
|
// nil SignedDataReader
|
||||||
|
_, err := SignedDataFromReader(nil)
|
||||||
|
require.EqualError(t, err, ErrNilSignedDataReader.Error())
|
||||||
|
|
||||||
|
rdr := &testSignedDataReader{
|
||||||
|
testSignedDataSrc: new(testSignedDataSrc),
|
||||||
|
}
|
||||||
|
|
||||||
|
// make reader to return an error
|
||||||
|
rdr.err = errors.New("test error")
|
||||||
|
|
||||||
|
_, err = SignedDataFromReader(rdr)
|
||||||
|
require.EqualError(t, err, rdr.err.Error())
|
||||||
|
|
||||||
|
// remove the error
|
||||||
|
rdr.err = nil
|
||||||
|
|
||||||
|
// fill the data
|
||||||
|
rdr.data = testData(t, 10)
|
||||||
|
|
||||||
|
res, err := SignedDataFromReader(rdr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, rdr.data, res)
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
const signedRequestDataSize = 0 +
|
const signedRequestDataSize = 0 +
|
||||||
|
@ -31,14 +32,7 @@ func (m *CreateRequest) SetOwnerID(id OwnerID) {
|
||||||
|
|
||||||
// SignedData returns payload bytes of the request.
|
// SignedData returns payload bytes of the request.
|
||||||
func (m CreateRequest) SignedData() ([]byte, error) {
|
func (m CreateRequest) SignedData() ([]byte, error) {
|
||||||
data := make([]byte, m.SignedDataSize())
|
return service.SignedDataFromReader(m)
|
||||||
|
|
||||||
_, err := m.ReadSignedData(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignedDataSize returns payload size of the request.
|
// SignedDataSize returns payload size of the request.
|
||||||
|
|
67
state/sign.go
Normal file
67
state/sign.go
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
//
|
||||||
|
// Always returns an empty slice.
|
||||||
|
func (m NetmapRequest) SignedData() ([]byte, error) {
|
||||||
|
return make([]byte, 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
//
|
||||||
|
// Always returns an empty slice.
|
||||||
|
func (m MetricsRequest) SignedData() ([]byte, error) {
|
||||||
|
return make([]byte, 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
//
|
||||||
|
// Always returns an empty slice.
|
||||||
|
func (m HealthRequest) SignedData() ([]byte, error) {
|
||||||
|
return make([]byte, 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
//
|
||||||
|
// Always returns an empty slice.
|
||||||
|
func (m DumpRequest) SignedData() ([]byte, error) {
|
||||||
|
return make([]byte, 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
//
|
||||||
|
// Always returns an empty slice.
|
||||||
|
func (m DumpVarsRequest) SignedData() ([]byte, error) {
|
||||||
|
return make([]byte, 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedData returns payload bytes of the request.
|
||||||
|
func (m ChangeStateRequest) SignedData() ([]byte, error) {
|
||||||
|
return service.SignedDataFromReader(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedDataSize returns payload size of the request.
|
||||||
|
func (m ChangeStateRequest) SignedDataSize() int {
|
||||||
|
return m.GetState().Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSignedData copies payload bytes to passed buffer.
|
||||||
|
//
|
||||||
|
// If the Request size is insufficient, io.ErrUnexpectedEOF returns.
|
||||||
|
func (m ChangeStateRequest) ReadSignedData(p []byte) (int, error) {
|
||||||
|
if len(p) < m.SignedDataSize() {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var off int
|
||||||
|
|
||||||
|
off += copy(p[off:], m.GetState().Bytes())
|
||||||
|
|
||||||
|
return off, nil
|
||||||
|
}
|
94
state/sign_test.go
Normal file
94
state/sign_test.go
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||||||
|
"github.com/nspcc-dev/neofs-crypto/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequestSign(t *testing.T) {
|
||||||
|
sk := test.DecodeKey(0)
|
||||||
|
|
||||||
|
type sigType interface {
|
||||||
|
service.SignedDataWithToken
|
||||||
|
service.SignKeyPairAccumulator
|
||||||
|
service.SignKeyPairSource
|
||||||
|
SetToken(*service.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []struct {
|
||||||
|
constructor func() sigType
|
||||||
|
payloadCorrupt []func(sigType)
|
||||||
|
}{
|
||||||
|
{ // NetmapRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(NetmapRequest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // MetricsRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(MetricsRequest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // HealthRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(HealthRequest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // DumpRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(DumpRequest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ // DumpVarsRequest
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(DumpVarsRequest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
constructor: func() sigType {
|
||||||
|
return new(ChangeStateRequest)
|
||||||
|
},
|
||||||
|
payloadCorrupt: []func(sigType){
|
||||||
|
func(s sigType) {
|
||||||
|
req := s.(*ChangeStateRequest)
|
||||||
|
|
||||||
|
req.SetState(req.GetState() + 1)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
{ // token corruptions
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
token := new(service.Token)
|
||||||
|
v.SetToken(token)
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
token.SetSessionKey(append(token.GetSessionKey(), 1))
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // payload corruptions
|
||||||
|
for _, corruption := range item.payloadCorrupt {
|
||||||
|
v := item.constructor()
|
||||||
|
|
||||||
|
require.NoError(t, service.SignDataWithSessionToken(sk, v))
|
||||||
|
|
||||||
|
require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
|
||||||
|
corruption(v)
|
||||||
|
|
||||||
|
require.Error(t, service.VerifyAccumulatedSignaturesWithToken(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
state/types.go
Normal file
24
state/types.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetState is a State field setter.
|
||||||
|
func (m *ChangeStateRequest) SetState(st ChangeStateRequest_State) {
|
||||||
|
m.State = st
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the state binary representation.
|
||||||
|
func (ChangeStateRequest_State) Size() int {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the state binary representation.
|
||||||
|
func (x ChangeStateRequest_State) Bytes() []byte {
|
||||||
|
data := make([]byte, x.Size())
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(data, uint32(x))
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
18
state/types_test.go
Normal file
18
state/types_test.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChangeStateRequestGettersSetters(t *testing.T) {
|
||||||
|
t.Run("state", func(t *testing.T) {
|
||||||
|
st := ChangeStateRequest_State(1)
|
||||||
|
m := new(ChangeStateRequest)
|
||||||
|
|
||||||
|
m.SetState(st)
|
||||||
|
|
||||||
|
require.Equal(t, st, m.GetState())
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in a new issue