From b9d30d613831de5f06bea5ef9a415c9ba719ce6d Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 11:59:39 +0300 Subject: [PATCH 01/18] accounting: implement SignedDataSource on BalanceRequest message --- accounting/sign.go | 33 ++++++++++++++++++++++++ accounting/sign_test.go | 54 ++++++++++++++++++++++++++++++++++++++++ accounting/types.go | 10 ++++++++ accounting/types_test.go | 9 +++++++ 4 files changed, 106 insertions(+) create mode 100644 accounting/sign.go create mode 100644 accounting/sign_test.go diff --git a/accounting/sign.go b/accounting/sign.go new file mode 100644 index 0000000..a42375f --- /dev/null +++ b/accounting/sign.go @@ -0,0 +1,33 @@ +package accounting + +import "io" + +// SignedData returns payload bytes of the request. +func (m BalanceRequest) 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 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 +} diff --git a/accounting/sign_test.go b/accounting/sign_test.go new file mode 100644 index 0000000..03eaf6c --- /dev/null +++ b/accounting/sign_test.go @@ -0,0 +1,54 @@ +package accounting + +import ( + "testing" + + "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) { + // create test OwnerID + ownerID := OwnerID{1, 2, 3} + + // create test BalanceRequest + req := new(BalanceRequest) + req.SetOwnerID(ownerID) + + // create test private key + sk := test.DecodeKey(0) + + items := []struct { + corrupt func() + restore func() + }{ + { + corrupt: func() { + ownerID[0]++ + req.SetOwnerID(ownerID) + }, + restore: func() { + ownerID[0]-- + req.SetOwnerID(ownerID) + }, + }, + } + + for _, item := range items { + // sign with private key + require.NoError(t, service.AddSignatureWithKey(sk, req)) + + // ascertain that verification is passed + require.NoError(t, service.VerifyAccumulatedSignatures(req)) + + // corrupt the request + item.corrupt() + + // ascertain that verification is failed + require.Error(t, service.VerifyAccumulatedSignatures(req)) + + // ascertain that request + item.restore() + } +} diff --git a/accounting/types.go b/accounting/types.go index 6a3b2e2..3ac637d 100644 --- a/accounting/types.go +++ b/accounting/types.go @@ -351,3 +351,13 @@ 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 +} diff --git a/accounting/types_test.go b/accounting/types_test.go index df81b46..e89c08c 100644 --- a/accounting/types_test.go +++ b/accounting/types_test.go @@ -84,3 +84,12 @@ 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()) +} From 6832d71d4870a43b48953d2c2aef23a99f9ad2a8 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 12:54:21 +0300 Subject: [PATCH 02/18] accounting: implement SignedDataSource on GetRequest message --- accounting/sign.go | 34 ++++++++++++++ accounting/sign_test.go | 95 ++++++++++++++++++++++++++++------------ accounting/types.go | 20 +++++++++ accounting/types_test.go | 20 +++++++++ 4 files changed, 142 insertions(+), 27 deletions(-) diff --git a/accounting/sign.go b/accounting/sign.go index a42375f..8faeb96 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -31,3 +31,37 @@ func (m BalanceRequest) ReadSignedData(p []byte) (int, error) { return sz, nil } + +// SignedData returns payload bytes of the request. +func (m GetRequest) 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 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 +} diff --git a/accounting/sign_test.go b/accounting/sign_test.go index 03eaf6c..d059ab4 100644 --- a/accounting/sign_test.go +++ b/accounting/sign_test.go @@ -9,46 +9,87 @@ import ( ) func TestSignBalanceRequest(t *testing.T) { - // create test OwnerID - ownerID := OwnerID{1, 2, 3} - - // create test BalanceRequest - req := new(BalanceRequest) - req.SetOwnerID(ownerID) - - // create test private key sk := test.DecodeKey(0) + type sigType interface { + service.SignedDataWithToken + service.SignKeyPairAccumulator + service.SignKeyPairSource + SetToken(*service.Token) + } + items := []struct { - corrupt func() - restore func() + constructor func() sigType + payloadCorrupt []func(sigType) }{ - { - corrupt: func() { - ownerID[0]++ - req.SetOwnerID(ownerID) + { // BalanceRequest + constructor: func() sigType { + return new(BalanceRequest) }, - restore: func() { - ownerID[0]-- - req.SetOwnerID(ownerID) + 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) + }, }, }, } for _, item := range items { - // sign with private key - require.NoError(t, service.AddSignatureWithKey(sk, req)) + { // token corruptions + v := item.constructor() - // ascertain that verification is passed - require.NoError(t, service.VerifyAccumulatedSignatures(req)) + token := new(service.Token) + v.SetToken(token) - // corrupt the request - item.corrupt() + require.NoError(t, service.SignDataWithSessionToken(sk, v)) - // ascertain that verification is failed - require.Error(t, service.VerifyAccumulatedSignatures(req)) + require.NoError(t, service.VerifyAccumulatedSignaturesWithToken(v)) - // ascertain that request - item.restore() + 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)) + } + } } } diff --git a/accounting/types.go b/accounting/types.go index 3ac637d..1e4e80a 100644 --- a/accounting/types.go +++ b/accounting/types.go @@ -361,3 +361,23 @@ func (m BalanceRequest) GetOwnerID() OwnerID { 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 +} diff --git a/accounting/types_test.go b/accounting/types_test.go index e89c08c..ea17a8a 100644 --- a/accounting/types_test.go +++ b/accounting/types_test.go @@ -93,3 +93,23 @@ func TestBalanceRequest_SetOwnerID(t *testing.T) { 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()) + }) +} From 8c492a7712b44f6fd49ceb5c977801697370e2b6 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 13:14:31 +0300 Subject: [PATCH 03/18] accounting: implement SignedDataSource on PutRequest message --- accounting/sign.go | 59 +++++++++++++++++++++++++++++++++++++++- accounting/sign_test.go | 44 ++++++++++++++++++++++++++++++ accounting/types.go | 30 ++++++++++++++++++++ accounting/types_test.go | 39 ++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 1 deletion(-) diff --git a/accounting/sign.go b/accounting/sign.go index 8faeb96..8da8cf6 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -1,6 +1,9 @@ package accounting -import "io" +import ( + "encoding/binary" + "io" +) // SignedData returns payload bytes of the request. func (m BalanceRequest) SignedData() ([]byte, error) { @@ -65,3 +68,57 @@ func (m GetRequest) ReadSignedData(p []byte) (int, error) { return sz, nil } + +// SignedData returns payload bytes of the request. +func (m PutRequest) 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 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 +} diff --git a/accounting/sign_test.go b/accounting/sign_test.go index d059ab4..1f88dcf 100644 --- a/accounting/sign_test.go +++ b/accounting/sign_test.go @@ -3,6 +3,7 @@ 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" @@ -60,6 +61,49 @@ func TestSignBalanceRequest(t *testing.T) { }, }, }, + { // 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()))) + } + }, + }, + }, } for _, item := range items { diff --git a/accounting/types.go b/accounting/types.go index 1e4e80a..3a4b15e 100644 --- a/accounting/types.go +++ b/accounting/types.go @@ -381,3 +381,33 @@ func (m GetRequest) GetOwnerID() OwnerID { 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 +} diff --git a/accounting/types_test.go b/accounting/types_test.go index ea17a8a..844ea70 100644 --- a/accounting/types_test.go +++ b/accounting/types_test.go @@ -113,3 +113,42 @@ func TestGetRequestGettersSetters(t *testing.T) { 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()) + }) +} From 81f537cda88329272b2d1cfe71eb2e9a7fec11d8 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 13:20:58 +0300 Subject: [PATCH 04/18] accounting: implement SignedDataSource on ListRequest message --- accounting/sign.go | 30 ++++++++++++++++++++++++++++++ accounting/sign_test.go | 15 +++++++++++++++ accounting/types.go | 10 ++++++++++ accounting/types_test.go | 9 +++++++++ 4 files changed, 64 insertions(+) diff --git a/accounting/sign.go b/accounting/sign.go index 8da8cf6..dc8f6d7 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -122,3 +122,33 @@ func (m PutRequest) ReadSignedData(p []byte) (int, error) { return off, nil } + +// SignedData returns payload bytes of the request. +func (m ListRequest) 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 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 +} diff --git a/accounting/sign_test.go b/accounting/sign_test.go index 1f88dcf..77ee014 100644 --- a/accounting/sign_test.go +++ b/accounting/sign_test.go @@ -104,6 +104,21 @@ func TestSignBalanceRequest(t *testing.T) { }, }, }, + { // 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 { diff --git a/accounting/types.go b/accounting/types.go index 3a4b15e..8ea52e3 100644 --- a/accounting/types.go +++ b/accounting/types.go @@ -411,3 +411,13 @@ func (m *PutRequest) SetAmount(amount *decimal.Decimal) { 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 +} diff --git a/accounting/types_test.go b/accounting/types_test.go index 844ea70..cdf5610 100644 --- a/accounting/types_test.go +++ b/accounting/types_test.go @@ -152,3 +152,12 @@ func TestPutRequestGettersSetters(t *testing.T) { 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()) +} From 3fb293543f0e61b91c2fa830c425032bb21e0953 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 13:29:04 +0300 Subject: [PATCH 05/18] accounting: implement SignedDataSource on DeleteRequest message --- accounting/sign.go | 38 ++++++++++++++++++++++++++++++++++++++ accounting/sign_test.go | 31 +++++++++++++++++++++++++++++++ accounting/types.go | 30 ++++++++++++++++++++++++++++++ accounting/types_test.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) diff --git a/accounting/sign.go b/accounting/sign.go index dc8f6d7..b52d229 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -152,3 +152,41 @@ func (m ListRequest) ReadSignedData(p []byte) (int, error) { return sz, nil } + +// SignedData returns payload bytes of the request. +func (m DeleteRequest) 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 DeleteRequest) SignedDataSize() int { + return 0 + + m.GetID().Size() + + m.GetOwnerID().Size() + + m.GetMessageID().Size() +} + +// 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 +} diff --git a/accounting/sign_test.go b/accounting/sign_test.go index 77ee014..dd7a819 100644 --- a/accounting/sign_test.go +++ b/accounting/sign_test.go @@ -119,6 +119,37 @@ func TestSignBalanceRequest(t *testing.T) { }, }, }, + { + 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 { diff --git a/accounting/types.go b/accounting/types.go index 8ea52e3..e16fa99 100644 --- a/accounting/types.go +++ b/accounting/types.go @@ -421,3 +421,33 @@ func (m ListRequest) GetOwnerID() OwnerID { 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 +} diff --git a/accounting/types_test.go b/accounting/types_test.go index cdf5610..a440028 100644 --- a/accounting/types_test.go +++ b/accounting/types_test.go @@ -161,3 +161,33 @@ func TestListRequestGettersSetters(t *testing.T) { 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()) + }) +} From 9327c5f816f4624f7db1e9709d4a25a0f7464ac0 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 13:57:23 +0300 Subject: [PATCH 06/18] bootstrap: implement SignedDataSource on Request message --- accounting/sign.go | 13 ++++--- bootstrap/sign.go | 48 ++++++++++++++++++++++++ bootstrap/sign_test.go | 82 +++++++++++++++++++++++++++++++++++++++++ bootstrap/types.go | 35 ++++++++++++++++++ bootstrap/types_test.go | 39 ++++++++++++++++++++ service/role.go | 14 +++++++ 6 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 bootstrap/sign.go create mode 100644 bootstrap/sign_test.go create mode 100644 bootstrap/types_test.go diff --git a/accounting/sign.go b/accounting/sign.go index b52d229..4c6452d 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -165,11 +165,14 @@ func (m DeleteRequest) SignedData() ([]byte, error) { } // SignedDataSize returns payload size of the request. -func (m DeleteRequest) SignedDataSize() int { - return 0 + - m.GetID().Size() + - m.GetOwnerID().Size() + - m.GetMessageID().Size() +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. diff --git a/bootstrap/sign.go b/bootstrap/sign.go new file mode 100644 index 0000000..97d8640 --- /dev/null +++ b/bootstrap/sign.go @@ -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 +} diff --git a/bootstrap/sign_test.go b/bootstrap/sign_test.go new file mode 100644 index 0000000..2c76117 --- /dev/null +++ b/bootstrap/sign_test.go @@ -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)) + } + } + } +} diff --git a/bootstrap/types.go b/bootstrap/types.go index 690d81c..eacc41e 100644 --- a/bootstrap/types.go +++ b/bootstrap/types.go @@ -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,35 @@ 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 +} + +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 +} diff --git a/bootstrap/types_test.go b/bootstrap/types_test.go new file mode 100644 index 0000000..20b1b1a --- /dev/null +++ b/bootstrap/types_test.go @@ -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()) + }) +} diff --git a/service/role.go b/service/role.go index 4c405c1..3af09ab 100644 --- a/service/role.go +++ b/service/role.go @@ -1,5 +1,7 @@ package service +import "encoding/binary" + const ( _ NodeRole = iota // InnerRingNode that work like IR node. @@ -19,3 +21,15 @@ func (nt NodeRole) String() string { 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 +} From 2d53ebf9c42dcfc95c8675c1083570a06c631614 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 14:37:16 +0300 Subject: [PATCH 07/18] container: implement SignedDataSource on PutRequest message --- container/sign.go | 66 +++++++++++++++++++++++++++ container/sign_test.go | 98 +++++++++++++++++++++++++++++++++++++++++ container/types.go | 35 +++++++++++++++ container/types_test.go | 52 ++++++++++++++++++++++ 4 files changed, 251 insertions(+) create mode 100644 container/sign.go create mode 100644 container/sign_test.go diff --git a/container/sign.go b/container/sign.go new file mode 100644 index 0000000..f551989 --- /dev/null +++ b/container/sign.go @@ -0,0 +1,66 @@ +package container + +import ( + "encoding/binary" + "io" +) + +var requestEndianness = binary.BigEndian + +// SignedData returns payload bytes of the request. +func (m PutRequest) 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 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 +} diff --git a/container/sign_test.go b/container/sign_test.go new file mode 100644 index 0000000..f1476ed --- /dev/null +++ b/container/sign_test.go @@ -0,0 +1,98 @@ +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) + }{ + { // Request + 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) + }, + }, + }, + } + + 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)) + } + } + } +} diff --git a/container/types.go b/container/types.go index e358e6d..39cef43 100644 --- a/container/types.go +++ b/container/types.go @@ -93,3 +93,38 @@ 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 +} diff --git a/container/types_test.go b/container/types_test.go index fddccb3..07298bc 100644 --- a/container/types_test.go +++ b/container/types_test.go @@ -55,3 +55,55 @@ 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()) + }) +} From eedb97d1355437461b71c02d7aff8cafb43786d7 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 15:01:29 +0300 Subject: [PATCH 08/18] container: implement SignedDataSource on DeleteRequest message --- container/sign.go | 31 +++++++++++++++++++++++++++++++ container/sign_test.go | 17 ++++++++++++++++- container/types.go | 10 ++++++++++ container/types_test.go | 11 +++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/container/sign.go b/container/sign.go index f551989..d9405b8 100644 --- a/container/sign.go +++ b/container/sign.go @@ -64,3 +64,34 @@ func (m PutRequest) ReadSignedData(p []byte) (int, error) { return off, nil } + +// SignedData returns payload bytes of the request. +func (m DeleteRequest) 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 DeleteRequest) SignedDataSize() (sz 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 +} diff --git a/container/sign_test.go b/container/sign_test.go index f1476ed..caa3516 100644 --- a/container/sign_test.go +++ b/container/sign_test.go @@ -22,7 +22,7 @@ func TestRequestSign(t *testing.T) { constructor func() sigType payloadCorrupt []func(sigType) }{ - { // Request + { // PutRequest constructor: func() sigType { return new(PutRequest) }, @@ -63,6 +63,21 @@ func TestRequestSign(t *testing.T) { }, }, }, + { // DeleteRequest + constructor: func() sigType { + return new(DeleteRequest) + }, + payloadCorrupt: []func(sigType){ + func(s sigType) { + req := s.(*DeleteRequest) + + cid := req.GetCID() + cid[0]++ + + req.SetCID(cid) + }, + }, + }, } for _, item := range items { diff --git a/container/types.go b/container/types.go index 39cef43..eeabe35 100644 --- a/container/types.go +++ b/container/types.go @@ -128,3 +128,13 @@ func (m *PutRequest) SetRules(rules netmap.PlacementRule) { 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 +} diff --git a/container/types_test.go b/container/types_test.go index 07298bc..c1dafcc 100644 --- a/container/types_test.go +++ b/container/types_test.go @@ -107,3 +107,14 @@ func TestPutRequestGettersSetters(t *testing.T) { 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()) + }) +} From a41f22782b588ae4b250974ab2f5ed079f56ac5b Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 15:05:03 +0300 Subject: [PATCH 09/18] container: implement SignedDataSource on GetRequest message --- container/sign.go | 31 +++++++++++++++++++++++++++++++ container/sign_test.go | 15 +++++++++++++++ container/types.go | 10 ++++++++++ container/types_test.go | 11 +++++++++++ 4 files changed, 67 insertions(+) diff --git a/container/sign.go b/container/sign.go index d9405b8..89c4a4c 100644 --- a/container/sign.go +++ b/container/sign.go @@ -95,3 +95,34 @@ func (m DeleteRequest) ReadSignedData(p []byte) (int, error) { return off, nil } + +// SignedData returns payload bytes of the request. +func (m GetRequest) 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 GetRequest) SignedDataSize() (sz 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 +} diff --git a/container/sign_test.go b/container/sign_test.go index caa3516..fb11fab 100644 --- a/container/sign_test.go +++ b/container/sign_test.go @@ -74,6 +74,21 @@ func TestRequestSign(t *testing.T) { 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) }, }, diff --git a/container/types.go b/container/types.go index eeabe35..b34c51b 100644 --- a/container/types.go +++ b/container/types.go @@ -138,3 +138,13 @@ func (m DeleteRequest) GetCID() CID { 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 +} diff --git a/container/types_test.go b/container/types_test.go index c1dafcc..3c12072 100644 --- a/container/types_test.go +++ b/container/types_test.go @@ -118,3 +118,14 @@ func TestDeleteRequestGettersSetters(t *testing.T) { 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()) + }) +} From f91adcb5607f62095b4ca2f5343b9fe00af7a70e Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 15:17:11 +0300 Subject: [PATCH 10/18] container: implement SignedDataSource on ListRequest message --- container/sign.go | 35 +++++++++++++++++++++++++++++++++-- container/sign_test.go | 15 +++++++++++++++ container/types.go | 10 ++++++++++ container/types_test.go | 11 +++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/container/sign.go b/container/sign.go index 89c4a4c..0f5fc93 100644 --- a/container/sign.go +++ b/container/sign.go @@ -77,7 +77,7 @@ func (m DeleteRequest) SignedData() ([]byte, error) { } // SignedDataSize returns payload size of the request. -func (m DeleteRequest) SignedDataSize() (sz int) { +func (m DeleteRequest) SignedDataSize() int { return m.GetCID().Size() } @@ -108,7 +108,7 @@ func (m GetRequest) SignedData() ([]byte, error) { } // SignedDataSize returns payload size of the request. -func (m GetRequest) SignedDataSize() (sz int) { +func (m GetRequest) SignedDataSize() int { return m.GetCID().Size() } @@ -126,3 +126,34 @@ func (m GetRequest) ReadSignedData(p []byte) (int, error) { return off, nil } + +// SignedData returns payload bytes of the request. +func (m ListRequest) 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 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 +} diff --git a/container/sign_test.go b/container/sign_test.go index fb11fab..e469399 100644 --- a/container/sign_test.go +++ b/container/sign_test.go @@ -93,6 +93,21 @@ func TestRequestSign(t *testing.T) { }, }, }, + { // 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 { diff --git a/container/types.go b/container/types.go index b34c51b..f340aa5 100644 --- a/container/types.go +++ b/container/types.go @@ -148,3 +148,13 @@ func (m GetRequest) GetCID() CID { 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 +} diff --git a/container/types_test.go b/container/types_test.go index 3c12072..cc171cb 100644 --- a/container/types_test.go +++ b/container/types_test.go @@ -129,3 +129,14 @@ func TestGetRequestGettersSetters(t *testing.T) { 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()) + }) +} From 539e93e558a58c596f9fe8a4118f35d0a27760d3 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:05:41 +0300 Subject: [PATCH 11/18] state: implement SignedDataSource on NetmapRequest message --- state/sign.go | 8 ++++++ state/sign_test.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 state/sign.go create mode 100644 state/sign_test.go diff --git a/state/sign.go b/state/sign.go new file mode 100644 index 0000000..c0d4c7f --- /dev/null +++ b/state/sign.go @@ -0,0 +1,8 @@ +package state + +// SignedData returns payload bytes of the request. +// +// Always returns empty slice. +func (m NetmapRequest) SignedData() ([]byte, error) { + return make([]byte, 0), nil +} diff --git a/state/sign_test.go b/state/sign_test.go new file mode 100644 index 0000000..8f9a98f --- /dev/null +++ b/state/sign_test.go @@ -0,0 +1,62 @@ +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) + }, + }, + } + + 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)) + } + } + } +} From df9a04e5427f2adbc8d1f04a57f21be0a14c1e3e Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:11:17 +0300 Subject: [PATCH 12/18] state: implement SignedDataSource on MetricsRequest message --- state/sign.go | 7 +++++++ state/sign_test.go | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/state/sign.go b/state/sign.go index c0d4c7f..47edada 100644 --- a/state/sign.go +++ b/state/sign.go @@ -6,3 +6,10 @@ package state func (m NetmapRequest) SignedData() ([]byte, error) { return make([]byte, 0), nil } + +// SignedData returns payload bytes of the request. +// +// Always returns empty slice. +func (m MetricsRequest) SignedData() ([]byte, error) { + return make([]byte, 0), nil +} diff --git a/state/sign_test.go b/state/sign_test.go index 8f9a98f..2e8da40 100644 --- a/state/sign_test.go +++ b/state/sign_test.go @@ -27,6 +27,11 @@ func TestRequestSign(t *testing.T) { return new(NetmapRequest) }, }, + { // MetricsRequest + constructor: func() sigType { + return new(MetricsRequest) + }, + }, } for _, item := range items { From ea12eabaf6ec0f2f081f927b0df56c5ba4883284 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:12:49 +0300 Subject: [PATCH 13/18] state: implement SignedDataSource on HealthRequest message --- state/sign.go | 11 +++++++++-- state/sign_test.go | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/state/sign.go b/state/sign.go index 47edada..f2ddd8e 100644 --- a/state/sign.go +++ b/state/sign.go @@ -2,14 +2,21 @@ package state // SignedData returns payload bytes of the request. // -// Always returns empty slice. +// 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 empty slice. +// 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 +} diff --git a/state/sign_test.go b/state/sign_test.go index 2e8da40..b5b4912 100644 --- a/state/sign_test.go +++ b/state/sign_test.go @@ -32,6 +32,11 @@ func TestRequestSign(t *testing.T) { return new(MetricsRequest) }, }, + { // HealthRequest + constructor: func() sigType { + return new(HealthRequest) + }, + }, } for _, item := range items { From 603db9c3254808d679df1dfa39f50b43c5b46eab Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:15:31 +0300 Subject: [PATCH 14/18] state: implement SignedDataSource on DumpRequest message --- state/sign.go | 7 +++++++ state/sign_test.go | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/state/sign.go b/state/sign.go index f2ddd8e..aaf1a2d 100644 --- a/state/sign.go +++ b/state/sign.go @@ -20,3 +20,10 @@ func (m MetricsRequest) SignedData() ([]byte, error) { 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 +} diff --git a/state/sign_test.go b/state/sign_test.go index b5b4912..cc525bc 100644 --- a/state/sign_test.go +++ b/state/sign_test.go @@ -37,6 +37,11 @@ func TestRequestSign(t *testing.T) { return new(HealthRequest) }, }, + { // DumpRequest + constructor: func() sigType { + return new(DumpRequest) + }, + }, } for _, item := range items { From 5545b25a95de39ed790c471511cea420fa3d00ad Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:16:54 +0300 Subject: [PATCH 15/18] state: implement SignedDataSource on DumpVarsRequest message --- state/sign.go | 7 +++++++ state/sign_test.go | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/state/sign.go b/state/sign.go index aaf1a2d..8316b52 100644 --- a/state/sign.go +++ b/state/sign.go @@ -27,3 +27,10 @@ func (m HealthRequest) SignedData() ([]byte, error) { 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 +} diff --git a/state/sign_test.go b/state/sign_test.go index cc525bc..dd55d21 100644 --- a/state/sign_test.go +++ b/state/sign_test.go @@ -42,6 +42,11 @@ func TestRequestSign(t *testing.T) { return new(DumpRequest) }, }, + { // DumpVarsRequest + constructor: func() sigType { + return new(DumpVarsRequest) + }, + }, } for _, item := range items { From ab198b404966640a2c78a155d66cda816f639fe8 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 16:31:39 +0300 Subject: [PATCH 16/18] state: implement SignedDataSource on ChangeStateRequest message --- state/sign.go | 35 +++++++++++++++++++++++++++++++++++ state/sign_test.go | 12 ++++++++++++ state/types.go | 24 ++++++++++++++++++++++++ state/types_test.go | 18 ++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 state/types.go create mode 100644 state/types_test.go diff --git a/state/sign.go b/state/sign.go index 8316b52..9193ebc 100644 --- a/state/sign.go +++ b/state/sign.go @@ -1,5 +1,9 @@ package state +import ( + "io" +) + // SignedData returns payload bytes of the request. // // Always returns an empty slice. @@ -34,3 +38,34 @@ func (m DumpRequest) SignedData() ([]byte, error) { func (m DumpVarsRequest) SignedData() ([]byte, error) { return make([]byte, 0), nil } + +// SignedData returns payload bytes of the request. +func (m ChangeStateRequest) 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 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 +} diff --git a/state/sign_test.go b/state/sign_test.go index dd55d21..9b2bca9 100644 --- a/state/sign_test.go +++ b/state/sign_test.go @@ -47,6 +47,18 @@ func TestRequestSign(t *testing.T) { 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 { diff --git a/state/types.go b/state/types.go new file mode 100644 index 0000000..6b572db --- /dev/null +++ b/state/types.go @@ -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 +} diff --git a/state/types_test.go b/state/types_test.go new file mode 100644 index 0000000..5d5f5de --- /dev/null +++ b/state/types_test.go @@ -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()) + }) +} From e01fb0cc625ab164b3d15cc951c49b5aeab50a9a Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 17:28:44 +0300 Subject: [PATCH 17/18] Implement signed data calculating function from SignedDataReader --- accounting/sign.go | 42 +++-------------- bootstrap/sign.go | 14 +++--- container/sign.go | 34 +++----------- object/sign.go | 103 ++++++++++++++++++------------------------ service/errors.go | 4 ++ service/token.go | 6 +-- service/utils.go | 18 ++++++++ service/utils_test.go | 34 ++++++++++++++ session/request.go | 10 +--- state/sign.go | 10 ++-- 10 files changed, 126 insertions(+), 149 deletions(-) create mode 100644 service/utils.go create mode 100644 service/utils_test.go diff --git a/accounting/sign.go b/accounting/sign.go index 4c6452d..1eabed4 100644 --- a/accounting/sign.go +++ b/accounting/sign.go @@ -3,17 +3,13 @@ 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) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -37,13 +33,7 @@ func (m BalanceRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m GetRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -71,13 +61,7 @@ func (m GetRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m PutRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -125,13 +109,7 @@ func (m PutRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m ListRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -155,13 +133,7 @@ func (m ListRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m DeleteRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. diff --git a/bootstrap/sign.go b/bootstrap/sign.go index 97d8640..34f7fc2 100644 --- a/bootstrap/sign.go +++ b/bootstrap/sign.go @@ -1,16 +1,14 @@ package bootstrap -import "io" +import ( + "io" + + "github.com/nspcc-dev/neofs-api-go/service" +) // 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 + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. diff --git a/container/sign.go b/container/sign.go index 0f5fc93..eafd93c 100644 --- a/container/sign.go +++ b/container/sign.go @@ -3,19 +3,15 @@ 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) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -67,13 +63,7 @@ func (m PutRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m DeleteRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -98,13 +88,7 @@ func (m DeleteRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m GetRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. @@ -129,13 +113,7 @@ func (m GetRequest) ReadSignedData(p []byte) (int, error) { // SignedData returns payload bytes of the request. func (m ListRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. diff --git a/object/sign.go b/object/sign.go index 25d0b2f..1ed3efa 100644 --- a/object/sign.go +++ b/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. diff --git a/service/errors.go b/service/errors.go index 6241ad2..f3a0dfc 100644 --- a/service/errors.go +++ b/service/errors.go @@ -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") diff --git a/service/token.go b/service/token.go index 78fccfa..32c390f 100644 --- a/service/token.go +++ b/service/token.go @@ -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. diff --git a/service/utils.go b/service/utils.go new file mode 100644 index 0000000..17b23bb --- /dev/null +++ b/service/utils.go @@ -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 +} diff --git a/service/utils_test.go b/service/utils_test.go new file mode 100644 index 0000000..60a2352 --- /dev/null +++ b/service/utils_test.go @@ -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) +} diff --git a/session/request.go b/session/request.go index 0bb5176..73c05e5 100644 --- a/session/request.go +++ b/session/request.go @@ -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. diff --git a/state/sign.go b/state/sign.go index 9193ebc..88f038c 100644 --- a/state/sign.go +++ b/state/sign.go @@ -2,6 +2,8 @@ package state import ( "io" + + "github.com/nspcc-dev/neofs-api-go/service" ) // SignedData returns payload bytes of the request. @@ -41,13 +43,7 @@ func (m DumpVarsRequest) SignedData() ([]byte, error) { // SignedData returns payload bytes of the request. func (m ChangeStateRequest) SignedData() ([]byte, error) { - data := make([]byte, m.SignedDataSize()) - - if _, err := m.ReadSignedData(data); err != nil { - return nil, err - } - - return data, nil + return service.SignedDataFromReader(m) } // SignedDataSize returns payload size of the request. From b2543c073977b63d8e73f5a2bef9865897fcdecd Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 11 May 2020 17:44:59 +0300 Subject: [PATCH 18/18] fix comments --- bootstrap/types.go | 2 ++ service/role.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bootstrap/types.go b/bootstrap/types.go index eacc41e..7ad3ec2 100644 --- a/bootstrap/types.go +++ b/bootstrap/types.go @@ -122,10 +122,12 @@ 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()) diff --git a/service/role.go b/service/role.go index 3af09ab..64a0074 100644 --- a/service/role.go +++ b/service/role.go @@ -22,10 +22,12 @@ func (nt NodeRole) String() string { } } +// 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())