bootstrap: implement SignedDataSource on Request message

This commit is contained in:
Leonard Lyubich 2020-05-11 13:57:23 +03:00
parent 3fb293543f
commit 9327c5f816
6 changed files with 226 additions and 5 deletions

View file

@ -165,11 +165,14 @@ func (m DeleteRequest) SignedData() ([]byte, error) {
} }
// SignedDataSize returns payload size of the request. // SignedDataSize returns payload size of the request.
func (m DeleteRequest) SignedDataSize() int { func (m DeleteRequest) SignedDataSize() (sz int) {
return 0 + sz += m.GetID().Size()
m.GetID().Size() +
m.GetOwnerID().Size() + sz += m.GetOwnerID().Size()
m.GetMessageID().Size()
sz += m.GetMessageID().Size()
return
} }
// ReadSignedData copies payload bytes to passed buffer. // ReadSignedData copies payload bytes to passed buffer.

48
bootstrap/sign.go Normal file
View file

@ -0,0 +1,48 @@
package bootstrap
import "io"
// SignedData returns payload bytes of the request.
func (m Request) SignedData() ([]byte, error) {
data := make([]byte, m.SignedDataSize())
if _, err := m.ReadSignedData(data); err != nil {
return nil, err
}
return data, nil
}
// 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
View 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))
}
}
}
}

View file

@ -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,35 @@ 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
}
func (x Request_State) Size() int {
return 4
}
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
View 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())
})
}

View file

@ -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,15 @@ func (nt NodeRole) String() string {
return "Unknown" return "Unknown"
} }
} }
func (nt NodeRole) Size() int {
return 4
}
func (nt NodeRole) Bytes() []byte {
data := make([]byte, nt.Size())
binary.BigEndian.PutUint32(data, uint32(nt))
return data
}