Merge branch 'release/0.2.8'

This commit is contained in:
Evgeniy Kulikov 2019-12-21 12:25:45 +03:00
commit abc3c371ce
No known key found for this signature in database
GPG key ID: BF6AEE0A2A699BF2
10 changed files with 144 additions and 5 deletions

View file

@ -1,6 +1,15 @@
# Changelog # Changelog
This is the changelog for NeoFS Proto This is the changelog for NeoFS Proto
## [0.2.8] - 2019-12-21
### Added
- Container access control type definitions
### Changed
- Used sync.Pool for Sign/VerifyRequestHeader
- VerifiableRequest.Marshal method replace with MarshalTo and Size
## [0.2.7] - 2019-12-17 ## [0.2.7] - 2019-12-17
### Fixed ### Fixed
@ -78,3 +87,4 @@ Initial public release
[0.2.5]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.4...v0.2.5 [0.2.5]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.4...v0.2.5
[0.2.6]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.5...v0.2.6 [0.2.6]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.5...v0.2.6
[0.2.7]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.6...v0.2.7 [0.2.7]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.6...v0.2.7
[0.2.8]: https://github.com/nspcc-dev/neofs-proto/compare/v0.2.7...v0.2.8

Binary file not shown.

View file

@ -41,6 +41,9 @@ message PutRequest {
// Rules define storage policy for the object inside the container. // Rules define storage policy for the object inside the container.
netmap.PlacementRule rules = 4 [(gogoproto.nullable) = false]; netmap.PlacementRule rules = 4 [(gogoproto.nullable) = false];
// Container ACL.
AccessGroup Group = 5 [(gogoproto.nullable) = false];
// RequestMetaHeader contains information about request meta headers (should be embedded into message) // RequestMetaHeader contains information about request meta headers (should be embedded into message)
service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
// RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message) // RequestVerificationHeader is a set of signatures of every NeoFS Node that processed request (should be embedded into message)

View file

@ -11,6 +11,19 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// AccessMode is a container access mode type.
type AccessMode uint32
const (
// AccessModeRead is a read access mode.
AccessModeRead AccessMode = 1 << iota
// AccessModeWrite is a write access mode.
AccessModeWrite
)
// AccessModeReadWrite is a read/write container access mode.
const AccessModeReadWrite = AccessModeRead | AccessModeWrite
var ( var (
_ internal.Custom = (*Container)(nil) _ internal.Custom = (*Container)(nil)

Binary file not shown.

View file

@ -17,4 +17,18 @@ message Container {
uint64 Capacity = 3; uint64 Capacity = 3;
// Rules define storage policy for the object inside the container. // Rules define storage policy for the object inside the container.
netmap.PlacementRule Rules = 4 [(gogoproto.nullable) = false]; netmap.PlacementRule Rules = 4 [(gogoproto.nullable) = false];
// Container ACL.
AccessControlList List = 5 [(gogoproto.nullable) = false];
}
message AccessGroup {
// Group access mode.
uint32 AccessMode = 1;
// Group members.
repeated bytes UserGroup = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false];
}
message AccessControlList {
// List of access groups.
repeated AccessGroup List = 1 [(gogoproto.nullable) = false];
} }

View file

@ -55,3 +55,23 @@ func TestCID(t *testing.T) {
require.Equal(t, cid1, cid2) require.Equal(t, cid1, cid2)
}) })
} }
func TestAccessMode(t *testing.T) {
t.Run("read access to read/write mode", func(t *testing.T) {
require.Equal(t, AccessModeRead, AccessModeReadWrite&AccessModeRead)
})
t.Run("write access to read/write mode", func(t *testing.T) {
require.Equal(t, AccessModeWrite, AccessModeReadWrite&AccessModeWrite)
})
t.Run("read(write) access to write(read) mode", func(t *testing.T) {
require.Zero(t, AccessModeRead&AccessModeWrite)
})
t.Run("access to same mode", func(t *testing.T) {
require.Equal(t, AccessModeWrite, AccessModeWrite&AccessModeWrite)
require.Equal(t, AccessModeRead, AccessModeRead&AccessModeRead)
require.Equal(t, AccessModeReadWrite, AccessModeReadWrite&AccessModeReadWrite)
})
}

3
go.mod
View file

@ -18,3 +18,6 @@ require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
google.golang.org/grpc v1.24.0 google.golang.org/grpc v1.24.0
) )
// Used for debug reasons
// replace github.com/nspcc-dev/neofs-crypto => ../neofs-crypto

View file

@ -2,6 +2,7 @@ package service
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"sync"
crypto "github.com/nspcc-dev/neofs-crypto" crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-proto/internal" "github.com/nspcc-dev/neofs-proto/internal"
@ -12,7 +13,8 @@ import (
type ( type (
// VerifiableRequest adds possibility to sign and verify request header. // VerifiableRequest adds possibility to sign and verify request header.
VerifiableRequest interface { VerifiableRequest interface {
Marshal() ([]byte, error) Size() int
MarshalTo([]byte) (int, error)
AddSignature(*RequestVerificationHeader_Signature) AddSignature(*RequestVerificationHeader_Signature)
GetSignatures() []*RequestVerificationHeader_Signature GetSignatures() []*RequestVerificationHeader_Signature
SetSignatures([]*RequestVerificationHeader_Signature) SetSignatures([]*RequestVerificationHeader_Signature)
@ -133,6 +135,10 @@ func newSignature(key *ecdsa.PrivateKey, data []byte) (*RequestVerificationHeade
}, nil }, nil
} }
var bytesPool = sync.Pool{New: func() interface{} {
return make([]byte, 4.5*1024*1024) // 4.5MB
}}
// SignRequestHeader receives private key and request with RequestVerificationHeader, // SignRequestHeader receives private key and request with RequestVerificationHeader,
// tries to marshal and sign request with passed PrivateKey, after that adds // tries to marshal and sign request with passed PrivateKey, after that adds
// new signature to headers. If something went wrong, returns error. // new signature to headers. If something went wrong, returns error.
@ -146,12 +152,23 @@ func SignRequestHeader(key *ecdsa.PrivateKey, msg VerifiableRequest) error {
}() }()
} }
data, err := msg.Marshal() data := bytesPool.Get().([]byte)
defer func() {
bytesPool.Put(data)
}()
if size := msg.Size(); size <= cap(data) {
data = data[:size]
} else {
data = make([]byte, size)
}
size, err := msg.MarshalTo(data)
if err != nil { if err != nil {
return err return err
} }
signature, err := newSignature(key, data) signature, err := newSignature(key, data[:size])
if err != nil { if err != nil {
return err return err
} }
@ -174,8 +191,10 @@ func VerifyRequestHeader(msg VerifiableRequest) error {
}() }()
} }
data := bytesPool.Get().([]byte)
signatures := msg.GetSignatures() signatures := msg.GetSignatures()
defer func() { defer func() {
bytesPool.Put(data)
msg.SetSignatures(signatures) msg.SetSignatures(signatures)
}() }()
@ -189,9 +208,15 @@ func VerifyRequestHeader(msg VerifiableRequest) error {
return errors.Wrapf(ErrCannotLoadPublicKey, "%d: %02x", i, peer) return errors.Wrapf(ErrCannotLoadPublicKey, "%d: %02x", i, peer)
} }
if data, err := msg.Marshal(); err != nil { if size := msg.Size(); size <= cap(data) {
data = data[:size]
} else {
data = make([]byte, size)
}
if size, err := msg.MarshalTo(data); err != nil {
return errors.Wrapf(err, "%d: %02x", i, peer) return errors.Wrapf(err, "%d: %02x", i, peer)
} else if err := crypto.Verify(key, data, sign); err != nil { } else if err := crypto.Verify(key, data[:size], sign); err != nil {
return errors.Wrapf(err, "%d: %02x", i, peer) return errors.Wrapf(err, "%d: %02x", i, peer)
} }
} }

View file

@ -14,6 +14,57 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func BenchmarkSignRequestHeader(b *testing.B) {
key := test.DecodeKey(0)
custom := testCustomField{1, 2, 3, 4, 5, 6, 7, 8}
some := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: make([]byte, 1<<22),
CustomField: &custom,
RequestMetaHeader: RequestMetaHeader{
TTL: math.MaxInt32 - 8,
Epoch: math.MaxInt64 - 12,
},
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
require.NoError(b, SignRequestHeader(key, some))
}
}
func BenchmarkVerifyRequestHeader(b *testing.B) {
custom := testCustomField{1, 2, 3, 4, 5, 6, 7, 8}
some := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: make([]byte, 1<<22),
CustomField: &custom,
RequestMetaHeader: RequestMetaHeader{
TTL: math.MaxInt32 - 8,
Epoch: math.MaxInt64 - 12,
},
}
for i := 0; i < 10; i++ {
key := test.DecodeKey(i)
require.NoError(b, SignRequestHeader(key, some))
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
require.NoError(b, VerifyRequestHeader(some))
}
}
func TestSignRequestHeader(t *testing.T) { func TestSignRequestHeader(t *testing.T) {
req := &TestRequest{ req := &TestRequest{
IntField: math.MaxInt32, IntField: math.MaxInt32,