forked from TrueCloudLab/frostfs-api-go
Merge branch 'release/0.2.8'
This commit is contained in:
commit
abc3c371ce
10 changed files with 144 additions and 5 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -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.
|
@ -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)
|
||||||
|
|
|
@ -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.
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
3
go.mod
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue