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)
|
||||
}
|
||||
|
||||
// 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))
|
||||
})
|
||||
}
|
||||
|
||||
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 (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -27,6 +28,8 @@ var (
|
|||
_ proto.Message = (*SpreadMap)(nil)
|
||||
)
|
||||
|
||||
var requestEndianness = binary.BigEndian
|
||||
|
||||
// Equals checks whether two NodeInfo has same address.
|
||||
func (m NodeInfo) Equals(n1 NodeInfo) bool {
|
||||
return m.Address == n1.Address && bytes.Equal(m.PubKey, n1.PubKey)
|
||||
|
@ -98,3 +101,37 @@ func (m SpreadMap) String() string {
|
|||
", " +
|
||||
"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)
|
||||
})
|
||||
}
|
||||
|
||||
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 (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
)
|
||||
|
||||
// SignedData returns payload bytes of the request.
|
||||
//
|
||||
// If payload is nil, ErrHeaderNotFound returns.
|
||||
func (m PutRequest) SignedData() ([]byte, error) {
|
||||
sz := m.SignedDataSize()
|
||||
if sz < 0 {
|
||||
return nil, ErrHeaderNotFound
|
||||
}
|
||||
|
||||
data := make([]byte, sz)
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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()
|
||||
if r == nil {
|
||||
return ErrHeaderNotFound
|
||||
return 0, ErrHeaderNotFound
|
||||
}
|
||||
|
||||
_, err := r.MarshalTo(p)
|
||||
|
||||
return err
|
||||
return r.MarshalTo(p)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (m GetRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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()
|
||||
|
||||
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.
|
||||
|
@ -76,28 +69,28 @@ func (m GetRequest) SignedDataSize() int {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m HeadRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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() {
|
||||
return io.ErrUnexpectedEOF
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
if m.GetFullHeaders() {
|
||||
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.
|
||||
|
@ -107,24 +100,24 @@ func (m HeadRequest) SignedDataSize() int {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m DeleteRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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() {
|
||||
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.
|
||||
|
@ -134,27 +127,25 @@ func (m DeleteRequest) SignedDataSize() int {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m GetRangeRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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() {
|
||||
return io.ErrUnexpectedEOF
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
n, err := (&m.Range).MarshalTo(p)
|
||||
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.
|
||||
|
@ -164,17 +155,15 @@ func (m GetRangeRequest) SignedDataSize() int {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m GetRangeHashRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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() {
|
||||
return io.ErrUnexpectedEOF
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var off int
|
||||
|
@ -185,7 +174,7 @@ func (m GetRangeHashRequest) ReadSignedData(p []byte) error {
|
|||
|
||||
off += copy(p[off:], m.GetSalt())
|
||||
|
||||
return nil
|
||||
return off, nil
|
||||
}
|
||||
|
||||
// SignedDataSize returns payload size of the request.
|
||||
|
@ -203,17 +192,15 @@ func (m GetRangeHashRequest) SignedDataSize() int {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m SearchRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
return data, m.ReadSignedData(data)
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// ReadSignedData copies payload bytes to passed buffer.
|
||||
//
|
||||
// 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() {
|
||||
return io.ErrUnexpectedEOF
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var off int
|
||||
|
@ -223,9 +210,9 @@ func (m SearchRequest) ReadSignedData(p []byte) error {
|
|||
binary.BigEndian.PutUint32(p[off:], m.GetQueryVersion())
|
||||
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.
|
||||
|
|
|
@ -43,3 +43,7 @@ const ErrNilDataWithTokenSignAccumulator = internal.Error("signed data with toke
|
|||
// ErrNilSignatureKeySourceWithToken is returned by functions that expect
|
||||
// a non-nil SignatureKeySourceWithToken, but received 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
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
const (
|
||||
_ NodeRole = iota
|
||||
// InnerRingNode that work like IR node.
|
||||
|
@ -19,3 +21,17 @@ func (nt NodeRole) String() string {
|
|||
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.
|
||||
func (m *Token) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
copyTokenSignedData(data, m)
|
||||
|
||||
return data, nil
|
||||
return SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// 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"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
)
|
||||
|
||||
const signedRequestDataSize = 0 +
|
||||
|
@ -31,14 +32,7 @@ func (m *CreateRequest) SetOwnerID(id OwnerID) {
|
|||
|
||||
// SignedData returns payload bytes of the request.
|
||||
func (m CreateRequest) SignedData() ([]byte, error) {
|
||||
data := make([]byte, m.SignedDataSize())
|
||||
|
||||
_, err := m.ReadSignedData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
return service.SignedDataFromReader(m)
|
||||
}
|
||||
|
||||
// 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