diff --git a/Makefile b/Makefile index 64b09397..9609923a 100644 --- a/Makefile +++ b/Makefile @@ -33,5 +33,5 @@ protoc: echo "${B}${G}⇒ Processing $$f ${R}"; \ protoc \ --proto_path=.:./vendor:/usr/local/include \ - --gofast_out=plugins=grpc,paths=source_relative:. $$f; \ + --gofast_out=plugins=grpc,paths=source_relative:. $$f; \ done diff --git a/accounting/service.go b/accounting/service.go index df74e588..ac1ceb50 100644 --- a/accounting/service.go +++ b/accounting/service.go @@ -31,9 +31,6 @@ const ( ErrEmptyParentAddress = internal.Error("empty parent address") ) -// SetTTL sets ttl to BalanceRequest to satisfy TTLRequest interface. -func (m BalanceRequest) SetTTL(v uint32) { m.TTL = v } - // SumFunds goes through all accounts and sums up active funds. func SumFunds(accounts []*Account) (res *decimal.Decimal) { res = decimal.Zero.Copy() diff --git a/accounting/service.pb.go b/accounting/service.pb.go index bc31ce1c..7a8a0869 100644 Binary files a/accounting/service.pb.go and b/accounting/service.pb.go differ diff --git a/accounting/service.proto b/accounting/service.proto index 9cfdb0f6..f2696c44 100644 --- a/accounting/service.proto +++ b/accounting/service.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package accounting; option go_package = "github.com/nspcc-dev/neofs-proto/accounting"; +import "service/meta.proto"; +import "service/verify.proto"; import "decimal/decimal.proto"; import "accounting/types.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; @@ -17,10 +19,11 @@ service Accounting { message BalanceRequest { // OwnerID is a wallet address - bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 2; + bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message BalanceResponse { diff --git a/accounting/withdraw.go b/accounting/withdraw.go index 3cd27666..0a8cf901 100644 --- a/accounting/withdraw.go +++ b/accounting/withdraw.go @@ -11,18 +11,6 @@ type ( MessageID = refs.MessageID ) -// SetTTL sets ttl to GetRequest to satisfy TTLRequest interface. -func (m *GetRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to PutRequest to satisfy TTLRequest interface. -func (m *PutRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to ListRequest to satisfy TTLRequest interface. -func (m *ListRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to DeleteRequest to satisfy TTLRequest interface. -func (m *DeleteRequest) SetTTL(v uint32) { m.TTL = v } - // SetSignature sets signature to PutRequest to satisfy SignedRequest interface. func (m *PutRequest) SetSignature(v []byte) { m.Signature = v } diff --git a/accounting/withdraw.pb.go b/accounting/withdraw.pb.go index f0e78aa5..a2116c01 100644 Binary files a/accounting/withdraw.pb.go and b/accounting/withdraw.pb.go differ diff --git a/accounting/withdraw.proto b/accounting/withdraw.proto index eb58d080..bb950ba4 100644 --- a/accounting/withdraw.proto +++ b/accounting/withdraw.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package accounting; option go_package = "github.com/nspcc-dev/neofs-proto/accounting"; +import "service/meta.proto"; +import "service/verify.proto"; import "decimal/decimal.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; @@ -34,12 +36,13 @@ message Item { message GetRequest { // ID is cheque identifier - bytes ID = 1 [(gogoproto.customtype) = "ChequeID", (gogoproto.nullable) = false]; + bytes ID = 1 [(gogoproto.customtype) = "ChequeID", (gogoproto.nullable) = false]; // OwnerID is a wallet address - bytes OwnerID = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 3; + bytes OwnerID = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message GetResponse { @@ -49,18 +52,19 @@ message GetResponse { message PutRequest { // OwnerID is a wallet address - bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; // Amount of funds - decimal.Decimal Amount = 2; + decimal.Decimal Amount = 2; // Height is the neo blockchain height until the cheque is valid - uint64 Height = 3; + uint64 Height = 3; // MessageID is a nonce for uniq request (UUIDv4) - bytes MessageID = 4 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; + bytes MessageID = 4 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; // Signature is a signature of the sent request - bytes Signature = 5; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 6; + bytes Signature = 5; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message PutResponse { // ID is cheque identifier @@ -69,10 +73,11 @@ message PutResponse { message ListRequest { // OwnerID is a wallet address - bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 2; + bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message ListResponse { @@ -82,16 +87,17 @@ message ListResponse { message DeleteRequest { // ID is cheque identifier - bytes ID = 1 [(gogoproto.customtype) = "ChequeID", (gogoproto.nullable) = false]; + bytes ID = 1 [(gogoproto.customtype) = "ChequeID", (gogoproto.nullable) = false]; // OwnerID is a wallet address - bytes OwnerID = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + bytes OwnerID = 2 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; // MessageID is a nonce for uniq request (UUIDv4) - bytes MessageID = 3 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; + bytes MessageID = 3 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; // Signature is a signature of the sent request - bytes Signature = 4; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 5; + bytes Signature = 4; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } // DeleteResponse is empty diff --git a/bootstrap/service.go b/bootstrap/service.go index 6d0d3ca9..e67ea6df 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -6,6 +6,3 @@ import ( // NodeType type alias. type NodeType = service.NodeRole - -// SetTTL sets ttl to Request to satisfy TTLRequest interface. -func (m *Request) SetTTL(v uint32) { m.TTL = v } diff --git a/bootstrap/service.pb.go b/bootstrap/service.pb.go index f00f814b..7165399a 100644 Binary files a/bootstrap/service.pb.go and b/bootstrap/service.pb.go differ diff --git a/bootstrap/service.proto b/bootstrap/service.proto index cde94dcd..f0bf755d 100644 --- a/bootstrap/service.proto +++ b/bootstrap/service.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package bootstrap; option go_package = "github.com/nspcc-dev/neofs-proto/bootstrap"; +import "service/meta.proto"; +import "service/verify.proto"; import "bootstrap/types.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; @@ -17,10 +19,11 @@ service Bootstrap { message Request { // Type is NodeType, can be InnerRingNode (type=1) or StorageNode (type=2) - int32 type = 1 [(gogoproto.customname) = "Type" , (gogoproto.nullable) = false, (gogoproto.customtype) = "NodeType"]; + int32 type = 1 [(gogoproto.customname) = "Type" , (gogoproto.nullable) = false, (gogoproto.customtype) = "NodeType"]; // Info contains information about node - bootstrap.NodeInfo info = 2 [(gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 3; + bootstrap.NodeInfo info = 2 [(gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } diff --git a/container/service.go b/container/service.go index 27f39e78..5f446dae 100644 --- a/container/service.go +++ b/container/service.go @@ -19,18 +19,6 @@ type ( MessageID = refs.MessageID ) -// SetTTL sets ttl to GetRequest to satisfy TTLRequest interface. -func (m *GetRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to PutRequest to satisfy TTLRequest interface. -func (m *PutRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to ListRequest to satisfy TTLRequest interface. -func (m *ListRequest) SetTTL(v uint32) { m.TTL = v } - -// SetTTL sets ttl to DeleteRequest to satisfy TTLRequest interface. -func (m *DeleteRequest) SetTTL(v uint32) { m.TTL = v } - // SetSignature sets signature to PutRequest to satisfy SignedRequest interface. func (m *PutRequest) SetSignature(v []byte) { m.Signature = v } diff --git a/container/service.pb.go b/container/service.pb.go index cfd401d9..8b98cfa5 100644 Binary files a/container/service.pb.go and b/container/service.pb.go differ diff --git a/container/service.proto b/container/service.proto index 1cf8227c..d4d50cae 100644 --- a/container/service.proto +++ b/container/service.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package container; option go_package = "github.com/nspcc-dev/neofs-proto/container"; +import "service/meta.proto"; +import "service/verify.proto"; import "container/types.proto"; import "github.com/nspcc-dev/netmap/selector.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; @@ -28,23 +30,24 @@ service Service { message PutRequest { // MessageID is a nonce for uniq container id calculation - bytes MessageID = 1 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; + bytes MessageID = 1 [(gogoproto.customtype) = "MessageID", (gogoproto.nullable) = false]; // Capacity defines amount of data that can be stored in the container (doesn't used for now). - uint64 Capacity = 2; + uint64 Capacity = 2; // OwnerID is a wallet address - bytes OwnerID = 3 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + bytes OwnerID = 3 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; // Rules define storage policy for the object inside the container. - netmap.PlacementRule rules = 4 [(gogoproto.nullable) = false]; + netmap.PlacementRule rules = 4 [(gogoproto.nullable) = false]; // Signature of the user (owner id) - bytes Signature = 5; + bytes Signature = 5; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 6; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message PutResponse { @@ -54,14 +57,15 @@ message PutResponse { message DeleteRequest { // CID (container id) is a SHA256 hash of the container structure - bytes CID = 1 [(gogoproto.customtype) = "CID", (gogoproto.nullable) = false]; - - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 2; + bytes CID = 1 [(gogoproto.customtype) = "CID", (gogoproto.nullable) = false]; // Signature of the container owner - bytes Signature = 3; + bytes Signature = 2; + + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } // DeleteResponse is empty because delete operation is asynchronous and done @@ -71,11 +75,12 @@ message DeleteResponse { } message GetRequest { // CID (container id) is a SHA256 hash of the container structure - bytes CID = 1 [(gogoproto.customtype) = "CID", (gogoproto.nullable) = false]; + bytes CID = 1 [(gogoproto.customtype) = "CID", (gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 2; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message GetResponse { @@ -85,11 +90,11 @@ message GetResponse { message ListRequest { // OwnerID is a wallet address - bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; - - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 2; + bytes OwnerID = 1 [(gogoproto.customtype) = "OwnerID", (gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message ListResponse { diff --git a/object/service.go b/object/service.go index 098f9c31..84825392 100644 --- a/object/service.go +++ b/object/service.go @@ -31,8 +31,7 @@ type ( // All object operations must have TTL, Epoch, Container ID and // permission of usage previous network map. Request interface { - service.TTLRequest - service.EpochRequest + service.MetaHeader CID() CID AllowPreviousNetMap() bool @@ -124,54 +123,6 @@ func (m *GetResponse) NotFull() bool { return checkIsNotFull(m) } // NotFull checks if protobuf stream provided whole object for put operation. func (m *PutRequest) NotFull() bool { return checkIsNotFull(m) } -// GetTTL returns TTL value from object put request. -func (m *PutRequest) GetTTL() uint32 { return m.GetHeader().TTL } - -// GetEpoch returns epoch value from object put request. -func (m *PutRequest) GetEpoch() uint64 { return m.GetHeader().GetEpoch() } - -// SetTTL sets TTL value into object put request. -func (m *PutRequest) SetTTL(ttl uint32) { m.GetHeader().TTL = ttl } - -// SetTTL sets TTL value into object get request. -func (m *GetRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetTTL sets TTL value into object head request. -func (m *HeadRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetTTL sets TTL value into object search request. -func (m *SearchRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetTTL sets TTL value into object delete request. -func (m *DeleteRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetTTL sets TTL value into object get range request. -func (m *GetRangeRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetTTL sets TTL value into object get range hash request. -func (m *GetRangeHashRequest) SetTTL(ttl uint32) { m.TTL = ttl } - -// SetEpoch sets epoch value into object put request. -func (m *PutRequest) SetEpoch(v uint64) { m.GetHeader().Epoch = v } - -// SetEpoch sets epoch value into object get request. -func (m *GetRequest) SetEpoch(v uint64) { m.Epoch = v } - -// SetEpoch sets epoch value into object head request. -func (m *HeadRequest) SetEpoch(v uint64) { m.Epoch = v } - -// SetEpoch sets epoch value into object search request. -func (m *SearchRequest) SetEpoch(v uint64) { m.Epoch = v } - -// SetEpoch sets epoch value into object delete request. -func (m *DeleteRequest) SetEpoch(v uint64) { m.Epoch = v } - -// SetEpoch sets epoch value into object get range request. -func (m *GetRangeRequest) SetEpoch(v uint64) { m.Epoch = v } - -// SetEpoch sets epoch value into object get range hash request. -func (m *GetRangeHashRequest) SetEpoch(v uint64) { m.Epoch = v } - // CID returns container id value from object put request. func (m *PutRequest) CID() CID { return m.GetHeader().Object.SystemHeader.CID } diff --git a/object/service.pb.go b/object/service.pb.go index b19ed936..d58d391d 100644 Binary files a/object/service.pb.go and b/object/service.pb.go differ diff --git a/object/service.proto b/object/service.proto index 7a971db0..6abe8ede 100644 --- a/object/service.proto +++ b/object/service.proto @@ -5,6 +5,8 @@ option go_package = "github.com/nspcc-dev/neofs-proto/object"; import "refs/types.proto"; import "object/types.proto"; import "session/types.proto"; +import "service/meta.proto"; +import "service/verify.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; option (gogoproto.stable_marshaler_all) = true; @@ -52,14 +54,12 @@ service Service { } message GetRequest { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Address of object (container id + object id) - refs.Address Address = 2 [(gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 3; + refs.Address Address = 1 [(gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message GetResponse { @@ -73,16 +73,10 @@ message GetResponse { message PutRequest { message PutHeader { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Object with at least container id and owner id fields - Object Object = 2; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 3; + Object Object = 1; // Token with session public key and user's signature - session.Token Token = 4; + session.Token Token = 2; } oneof R { @@ -91,6 +85,11 @@ message PutRequest { // Chunk should be a remaining message in stream should be chunks bytes Chunk = 2; } + + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message PutResponse { @@ -98,18 +97,16 @@ message PutResponse { refs.Address Address = 1 [(gogoproto.nullable) = false]; } message DeleteRequest { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Address of object (container id + object id) - refs.Address Address = 2 [(gogoproto.nullable) = false]; + refs.Address Address = 1 [(gogoproto.nullable) = false]; // OwnerID is a wallet address - bytes OwnerID = 3 [(gogoproto.nullable) = false, (gogoproto.customtype) = "OwnerID"]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 4; + bytes OwnerID = 2 [(gogoproto.nullable) = false, (gogoproto.customtype) = "OwnerID"]; // Token with session public key and user's signature - session.Token Token = 5; + session.Token Token = 3; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } // DeleteResponse is empty because we cannot guarantee permanent object removal @@ -117,16 +114,14 @@ message DeleteRequest { message DeleteResponse {} message HeadRequest { - // Epoch should be empty on user side, node sets epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Address of object (container id + object id) - refs.Address Address = 2 [(gogoproto.nullable) = false, (gogoproto.customtype) = "Address"]; + refs.Address Address = 1 [(gogoproto.nullable) = false, (gogoproto.customtype) = "Address"]; // FullHeaders can be set true for extended headers in the object - bool FullHeaders = 3; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 4; + bool FullHeaders = 2; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message HeadResponse { // Object without payload @@ -134,18 +129,16 @@ message HeadResponse { } message SearchRequest { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Version of search query format - uint32 Version = 2; + uint32 Version = 1; // ContainerID for searching the object - bytes ContainerID = 3 [(gogoproto.nullable) = false, (gogoproto.customtype) = "CID"]; + bytes ContainerID = 2 [(gogoproto.nullable) = false, (gogoproto.customtype) = "CID"]; // Query in the binary serialized format - bytes Query = 4; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 5; + bytes Query = 3; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message SearchResponse { @@ -154,16 +147,14 @@ message SearchResponse { } message GetRangeRequest { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Address of object (container id + object id) - refs.Address Address = 2 [(gogoproto.nullable) = false]; + refs.Address Address = 1 [(gogoproto.nullable) = false]; // Ranges of object's payload to return - repeated Range Ranges = 3 [(gogoproto.nullable) = false]; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 4; + repeated Range Ranges = 2 [(gogoproto.nullable) = false]; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message GetRangeResponse { @@ -172,18 +163,16 @@ message GetRangeResponse { } message GetRangeHashRequest { - // Epoch is set by user to 0, node set epoch to the actual value - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint64 Epoch = 1; // Address of object (container id + object id) - refs.Address Address = 2 [(gogoproto.nullable) = false]; + refs.Address Address = 1 [(gogoproto.nullable) = false]; // Ranges of object's payload to calculate homomorphic hash - repeated Range Ranges = 3 [(gogoproto.nullable) = false]; + repeated Range Ranges = 2 [(gogoproto.nullable) = false]; // Salt is used to XOR object's payload ranges before hashing, it can be nil - bytes Salt = 4; - // TTL must be larger than zero, it decreased in every neofs-node - // Deprecated: will be replaced with RequestMetaHeader (see develop branch) - uint32 TTL = 5; + bytes Salt = 3; + // RequestMetaHeader contains information about request meta headers (should be embedded into message) + 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) + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message GetRangeHashResponse { diff --git a/object/utils.go b/object/utils.go index 1799b24f..f74fa2f5 100644 --- a/object/utils.go +++ b/object/utils.go @@ -4,6 +4,7 @@ import ( "io" "code.cloudfoundry.org/bytefmt" + "github.com/nspcc-dev/neofs-proto/service" "github.com/nspcc-dev/neofs-proto/session" "github.com/pkg/errors" ) @@ -49,14 +50,11 @@ func SendPutRequest(s Service_PutClient, obj *Object, epoch uint64, ttl uint32) // into header of object put request. func MakePutRequestHeader(obj *Object, epoch uint64, ttl uint32, token *session.Token) *PutRequest { return &PutRequest{ - R: &PutRequest_Header{ - Header: &PutRequest_PutHeader{ - Epoch: epoch, - Object: obj, - TTL: ttl, - Token: token, - }, - }, + RequestMetaHeader: service.RequestMetaHeader{TTL: ttl, Epoch: epoch}, + R: &PutRequest_Header{Header: &PutRequest_PutHeader{ + Object: obj, + Token: token, + }}, } } diff --git a/service/meta.go b/service/meta.go new file mode 100644 index 00000000..cd3459ef --- /dev/null +++ b/service/meta.go @@ -0,0 +1,90 @@ +package service + +import ( + "github.com/nspcc-dev/neofs-proto/internal" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type ( + // MetaHeader contains meta information of request. + // It provides methods to get or set meta information + // and reset meta header. + MetaHeader interface { + ResetMeta() + + // TTLRequest to verify and update ttl requests. + GetTTL() uint32 + SetTTL(uint32) + + // EpochRequest gives possibility to get or set epoch in RPC Requests. + GetEpoch() uint64 + SetEpoch(v uint64) + } + + // TTLCondition is closure, that allows to validate request with ttl + TTLCondition func(ttl uint32) error +) + +const ( + // ZeroTTL is empty ttl, should produce ErrZeroTTL. + ZeroTTL = iota + + // NonForwardingTTL is a ttl that allows direct connections only. + NonForwardingTTL + + // SingleForwardingTTL is a ttl that allows connections through another node. + SingleForwardingTTL +) + +const ( + // ErrZeroTTL is raised when zero ttl is passed. + ErrZeroTTL = internal.Error("zero ttl") + + // ErrIncorrectTTL is raised when NonForwardingTTL is passed and NodeRole != InnerRingNode. + ErrIncorrectTTL = internal.Error("incorrect ttl") +) + +// SetTTL sets TTL to RequestMetaHeader +func (m *RequestMetaHeader) SetTTL(v uint32) { m.TTL = v } + +// SetEpoch sets Epoch to RequestMetaHeader +func (m *RequestMetaHeader) SetEpoch(v uint64) { m.Epoch = v } + +// ResetMeta sets RequestMetaHeader to empty value +func (m *RequestMetaHeader) ResetMeta() { m.Reset() } + +// IRNonForwarding condition that allows NonForwardingTTL only for IR +func IRNonForwarding(role NodeRole) TTLCondition { + return func(ttl uint32) error { + if ttl == NonForwardingTTL && role != InnerRingNode { + return ErrIncorrectTTL + } + + return nil + } +} + +// ProcessRequestTTL validates and update ttl requests. +func ProcessRequestTTL(req MetaHeader, cond ...TTLCondition) error { + var ttl = req.GetTTL() + + if ttl == ZeroTTL { + return status.New(codes.InvalidArgument, ErrZeroTTL.Error()).Err() + } + + for i := range cond { + if cond[i] == nil { + continue + } + + // check specific condition: + if err := cond[i](ttl); err != nil { + return status.New(codes.InvalidArgument, err.Error()).Err() + } + } + + req.SetTTL(ttl - 1) + + return nil +} diff --git a/service/meta.pb.go b/service/meta.pb.go new file mode 100644 index 00000000..9fbd2835 Binary files /dev/null and b/service/meta.pb.go differ diff --git a/service/meta.proto b/service/meta.proto new file mode 100644 index 00000000..4c09fb3c --- /dev/null +++ b/service/meta.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package service; +option go_package = "github.com/nspcc-dev/neofs-proto/service"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +option (gogoproto.stable_marshaler_all) = true; + +message RequestMetaHeader { + uint32 TTL = 1; + uint64 Epoch = 2; +} diff --git a/service/meta_test.go b/service/meta_test.go new file mode 100644 index 00000000..893ca5ee --- /dev/null +++ b/service/meta_test.go @@ -0,0 +1,70 @@ +package service + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type mockedRequest struct { + msg string + name string + role NodeRole + code codes.Code + RequestMetaHeader +} + +func TestMetaRequest(t *testing.T) { + tests := []mockedRequest{ + { + role: InnerRingNode, + name: "direct to ir node", + RequestMetaHeader: RequestMetaHeader{TTL: NonForwardingTTL}, + }, + { + role: StorageNode, + code: codes.InvalidArgument, + msg: ErrIncorrectTTL.Error(), + name: "direct to storage node", + RequestMetaHeader: RequestMetaHeader{TTL: NonForwardingTTL}, + }, + { + role: StorageNode, + msg: ErrZeroTTL.Error(), + code: codes.InvalidArgument, + name: "zero ttl", + RequestMetaHeader: RequestMetaHeader{TTL: ZeroTTL}, + }, + { + role: InnerRingNode, + name: "default to ir node", + RequestMetaHeader: RequestMetaHeader{TTL: SingleForwardingTTL}, + }, + { + role: StorageNode, + name: "default to storage node", + RequestMetaHeader: RequestMetaHeader{TTL: SingleForwardingTTL}, + }, + } + + for i := range tests { + tt := tests[i] + t.Run(tt.name, func(t *testing.T) { + before := tt.GetTTL() + err := ProcessRequestTTL(&tt, IRNonForwarding(tt.role)) + if tt.msg != "" { + require.Errorf(t, err, tt.msg) + + state, ok := status.FromError(err) + require.True(t, ok) + require.Equal(t, state.Code(), tt.code) + require.Equal(t, state.Message(), tt.msg) + } else { + require.NoError(t, err) + require.NotEqualf(t, before, tt.GetTTL(), "ttl should be changed: %d vs %d", before, tt.GetTTL()) + } + }) + } +} diff --git a/service/role_test.go b/service/role_test.go index a1f1cc06..01dbee26 100644 --- a/service/role_test.go +++ b/service/role_test.go @@ -1,8 +1,9 @@ package service import ( - "github.com/stretchr/testify/require" "testing" + + "github.com/stretchr/testify/require" ) func TestNodeRole_String(t *testing.T) { diff --git a/service/ttl.go b/service/ttl.go deleted file mode 100644 index 8ddf1dec..00000000 --- a/service/ttl.go +++ /dev/null @@ -1,45 +0,0 @@ -package service - -import ( - "github.com/nspcc-dev/neofs-proto/internal" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -// TTLRequest to verify and update ttl requests. -type TTLRequest interface { - GetTTL() uint32 - SetTTL(uint32) -} - -const ( - // ZeroTTL is empty ttl, should produce ErrZeroTTL. - ZeroTTL = iota - - // NonForwardingTTL is a ttl that allows direct connections only. - NonForwardingTTL - - // SingleForwardingTTL is a ttl that allows connections through another node. - SingleForwardingTTL - - // ErrZeroTTL is raised when zero ttl is passed. - ErrZeroTTL = internal.Error("zero ttl") - - // ErrIncorrectTTL is raised when NonForwardingTTL is passed and NodeRole != InnerRingNode. - ErrIncorrectTTL = internal.Error("incorrect ttl") -) - -// CheckTTLRequest validates and update ttl requests. -func CheckTTLRequest(req TTLRequest, role NodeRole) error { - var ttl = req.GetTTL() - - if ttl == ZeroTTL { - return status.New(codes.InvalidArgument, ErrZeroTTL.Error()).Err() - } else if ttl == NonForwardingTTL && role != InnerRingNode { - return status.New(codes.InvalidArgument, ErrIncorrectTTL.Error()).Err() - } - - req.SetTTL(ttl - 1) - - return nil -} diff --git a/service/ttl_test.go b/service/ttl_test.go deleted file mode 100644 index 13491984..00000000 --- a/service/ttl_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package service - -import ( - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "testing" -) - -type mockedRequest struct { - msg string - ttl uint32 - name string - role NodeRole - code codes.Code -} - -func (m *mockedRequest) SetTTL(v uint32) { m.ttl = v } -func (m mockedRequest) GetTTL() uint32 { return m.ttl } - -func TestCheckTTLRequest(t *testing.T) { - tests := []mockedRequest{ - { - ttl: NonForwardingTTL, - role: InnerRingNode, - name: "direct to ir node", - }, - { - ttl: NonForwardingTTL, - role: StorageNode, - code: codes.InvalidArgument, - msg: ErrIncorrectTTL.Error(), - name: "direct to storage node", - }, - { - ttl: ZeroTTL, - role: StorageNode, - msg: ErrZeroTTL.Error(), - code: codes.InvalidArgument, - name: "zero ttl", - }, - { - ttl: SingleForwardingTTL, - role: InnerRingNode, - name: "default to ir node", - }, - { - ttl: SingleForwardingTTL, - role: StorageNode, - name: "default to storage node", - }, - } - - for i := range tests { - tt := tests[i] - t.Run(tt.name, func(t *testing.T) { - before := tt.ttl - err := CheckTTLRequest(&tt, tt.role) - if tt.msg != "" { - require.Errorf(t, err, tt.msg) - - state, ok := status.FromError(err) - require.True(t, ok) - require.Equal(t, state.Code(), tt.code) - require.Equal(t, state.Message(), tt.msg) - } else { - require.NoError(t, err) - require.NotEqualf(t, before, tt.ttl, "ttl should be changed: %d vs %d", before, tt.ttl) - } - }) - } -} diff --git a/service/verify.go b/service/verify.go new file mode 100644 index 00000000..d8ede7ea --- /dev/null +++ b/service/verify.go @@ -0,0 +1,179 @@ +package service + +import ( + "crypto/ecdsa" + + "github.com/gogo/protobuf/proto" + crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/nspcc-dev/neofs-proto/internal" + "github.com/pkg/errors" +) + +type ( + // VerifiableRequest adds possibility to sign and verify request header + VerifiableRequest interface { + proto.Message + Marshal() ([]byte, error) + AddSignature(*RequestVerificationHeader_Signature) + GetSignatures() []*RequestVerificationHeader_Signature + SetSignatures([]*RequestVerificationHeader_Signature) + } + + // MaintainableRequest adds possibility to set and get (+validate) + // owner (client) public key from RequestVerificationHeader. + MaintainableRequest interface { + proto.Message + GetOwner() (*ecdsa.PublicKey, error) + SetOwner(*ecdsa.PublicKey, []byte) + GetLastPeer() (*ecdsa.PublicKey, error) + } +) + +const ( + // ErrCannotLoadPublicKey is raised when cannot unmarshal public key from RequestVerificationHeader_Sign + ErrCannotLoadPublicKey = internal.Error("cannot load public key") + + // ErrCannotFindOwner is raised when signatures empty in GetOwner + ErrCannotFindOwner = internal.Error("cannot find owner public key") +) + +// SetSignatures replaces signatures stored in RequestVerificationHeader +func (m *RequestVerificationHeader) SetSignatures(signatures []*RequestVerificationHeader_Signature) { + m.Signatures = signatures +} + +// AddSignature adds new Signature into RequestVerificationHeader +func (m *RequestVerificationHeader) AddSignature(sig *RequestVerificationHeader_Signature) { + if sig == nil { + return + } + m.Signatures = append(m.Signatures, sig) +} + +// SetOwner adds origin (sign and public key) of owner (client) into first signature. +func (m *RequestVerificationHeader) SetOwner(pub *ecdsa.PublicKey, sign []byte) { + if len(m.Signatures) == 0 || pub == nil { + return + } + + m.Signatures[0].Origin = &RequestVerificationHeader_Sign{ + Sign: sign, + Peer: crypto.MarshalPublicKey(pub), + } +} + +// GetOwner tries to get owner (client) public key from signatures. +// If signatures contains not empty Origin, we should try to validate, +// that session key was signed by owner (client), otherwise return error. +func (m *RequestVerificationHeader) GetOwner() (*ecdsa.PublicKey, error) { + if len(m.Signatures) == 0 { + return nil, ErrCannotFindOwner + } + + // if first signature contains origin, we should try to validate session key + if m.Signatures[0].Origin != nil { + owner := crypto.UnmarshalPublicKey(m.Signatures[0].Origin.Peer) + if owner == nil { + return nil, ErrCannotLoadPublicKey + } else if err := crypto.Verify(owner, m.Signatures[0].Peer, m.Signatures[0].Origin.Sign); err != nil { + return nil, errors.Wrap(err, "could not verify session token") + } + + return owner, nil + } else if key := crypto.UnmarshalPublicKey(m.Signatures[0].Peer); key != nil { + return key, nil + } + + return nil, ErrCannotLoadPublicKey +} + +// GetLastPeer tries to get last peer public key from signatures. +// If signatures has zero length, returns ErrCannotFindOwner. +// If signatures has length equal to one, uses GetOwner. +// Otherwise tries to unmarshal last peer public key. +func (m *RequestVerificationHeader) GetLastPeer() (*ecdsa.PublicKey, error) { + switch ln := len(m.Signatures); ln { + case 0: + return nil, ErrCannotFindOwner + case 1: + return m.GetOwner() + default: + if key := crypto.UnmarshalPublicKey(m.Signatures[ln-1].Peer); key != nil { + return key, nil + } + + return nil, ErrCannotLoadPublicKey + } +} + +func newSignature(key *ecdsa.PrivateKey, data []byte) (*RequestVerificationHeader_Signature, error) { + sign, err := crypto.Sign(key, data) + if err != nil { + return nil, err + } + + return &RequestVerificationHeader_Signature{ + RequestVerificationHeader_Sign: RequestVerificationHeader_Sign{ + Sign: sign, + Peer: crypto.MarshalPublicKey(&key.PublicKey), + }, + }, nil +} + +// SignRequestHeader receives private key and request with RequestVerificationHeader, +// tries to marshal and sign request with passed PrivateKey, after that adds +// new signature to headers. If something went wrong, returns error. +func SignRequestHeader(key *ecdsa.PrivateKey, req VerifiableRequest) error { + msg := proto.Clone(req).(VerifiableRequest) + + // ignore meta header + if meta, ok := msg.(MetaHeader); ok { + meta.ResetMeta() + } + + data, err := msg.Marshal() + if err != nil { + return err + } + + signature, err := newSignature(key, data) + if err != nil { + return err + } + + req.AddSignature(signature) + + return nil +} + +// VerifyRequestHeader receives request with RequestVerificationHeader, +// tries to marshal and verify each signature from request +// If something went wrong, returns error. +func VerifyRequestHeader(req VerifiableRequest) error { + msg := proto.Clone(req).(VerifiableRequest) + // ignore meta header + if meta, ok := msg.(MetaHeader); ok { + meta.ResetMeta() + } + + signatures := msg.GetSignatures() + + for i := range signatures { + msg.SetSignatures(signatures[:i]) + peer := signatures[i].GetPeer() + sign := signatures[i].GetSign() + + key := crypto.UnmarshalPublicKey(peer) + if key == nil { + return errors.Wrapf(ErrCannotLoadPublicKey, "%d: %02x", i, peer) + } + + if data, err := msg.Marshal(); err != nil { + return errors.Wrapf(err, "%d: %02x", i, peer) + } else if err := crypto.Verify(key, data, sign); err != nil { + return errors.Wrapf(err, "%d: %02x", i, peer) + } + } + + return nil +} diff --git a/service/verify.pb.go b/service/verify.pb.go new file mode 100644 index 00000000..3c0f357e Binary files /dev/null and b/service/verify.pb.go differ diff --git a/service/verify.proto b/service/verify.proto new file mode 100644 index 00000000..7d833089 --- /dev/null +++ b/service/verify.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package service; +option go_package = "github.com/nspcc-dev/neofs-proto/service"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +option (gogoproto.stable_marshaler_all) = true; + +message RequestVerificationHeader { + message Sign { + bytes Sign = 1; + bytes Peer = 2; + } + message Signature { + Sign Sign = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + Sign Origin = 2; + } + + repeated Signature Signatures = 1; +} diff --git a/service/verify_test.go b/service/verify_test.go new file mode 100644 index 00000000..4aaefb47 --- /dev/null +++ b/service/verify_test.go @@ -0,0 +1,106 @@ +package service + +import ( + "math" + "testing" + + crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/nspcc-dev/neofs-crypto/test" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" +) + +func TestSignRequestHeader(t *testing.T) { + req := &TestRequest{ + IntField: math.MaxInt32, + StringField: "TestRequestStringField", + BytesField: []byte("TestRequestBytesField"), + } + + key := test.DecodeKey(0) + peer := crypto.MarshalPublicKey(&key.PublicKey) + + data, err := req.Marshal() + require.NoError(t, err) + + require.NoError(t, SignRequestHeader(key, req)) + + require.Len(t, req.Signatures, 1) + for i := range req.Signatures { + sign := req.Signatures[i].GetSign() + require.Equal(t, peer, req.Signatures[i].GetPeer()) + require.NoError(t, crypto.Verify(&key.PublicKey, data, sign)) + } +} + +func TestVerifyRequestHeader(t *testing.T) { + req := &TestRequest{ + IntField: math.MaxInt32, + StringField: "TestRequestStringField", + BytesField: []byte("TestRequestBytesField"), + RequestMetaHeader: RequestMetaHeader{TTL: 10}, + } + + for i := 0; i < 10; i++ { + req.TTL-- + require.NoError(t, SignRequestHeader(test.DecodeKey(i), req)) + } + + require.NoError(t, VerifyRequestHeader(req)) +} + +func TestMaintainableRequest(t *testing.T) { + req := &TestRequest{ + IntField: math.MaxInt32, + StringField: "TestRequestStringField", + BytesField: []byte("TestRequestBytesField"), + RequestMetaHeader: RequestMetaHeader{TTL: 10}, + } + + count := 10 + owner := test.DecodeKey(count + 1) + + for i := 0; i < count; i++ { + req.TTL-- + + key := test.DecodeKey(i) + require.NoError(t, SignRequestHeader(key, req)) + + // sign first key (session key) by owner key + if i == 0 { + sign, err := crypto.Sign(owner, crypto.MarshalPublicKey(&key.PublicKey)) + require.NoError(t, err) + + req.SetOwner(&owner.PublicKey, sign) + } + } + + { // Good case: + require.NoError(t, VerifyRequestHeader(req)) + + // validate, that first key (session key) was signed with owner + signatures := req.GetSignatures() + + require.Len(t, signatures, count) + + pub, err := req.GetOwner() + require.NoError(t, err) + + require.Equal(t, &owner.PublicKey, pub) + } + + { // wrong owner: + req.Signatures[0].Origin = nil + + pub, err := req.GetOwner() + require.NoError(t, err) + + require.NotEqual(t, &owner.PublicKey, pub) + } + + { // Wrong signatures: + copy(req.Signatures[count-1].Sign, req.Signatures[count-1].Peer) + err := VerifyRequestHeader(req) + require.EqualError(t, errors.Cause(err), crypto.ErrInvalidSignature.Error()) + } +} diff --git a/service/verify_test.pb.go b/service/verify_test.pb.go new file mode 100644 index 00000000..a029c2e2 Binary files /dev/null and b/service/verify_test.pb.go differ diff --git a/service/verify_test.proto b/service/verify_test.proto new file mode 100644 index 00000000..5eb8cfdf --- /dev/null +++ b/service/verify_test.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package service; +option go_package = "github.com/nspcc-dev/neofs-proto/service"; + +import "service/meta.proto"; +import "service/verify.proto"; +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +option (gogoproto.stable_marshaler_all) = true; + +message TestRequest { + int32 IntField = 1; + string StringField = 2; + bytes BytesField = 3; + RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + RequestVerificationHeader Header = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; +} diff --git a/session/service.pb.go b/session/service.pb.go index b99b611d..eef58192 100644 Binary files a/session/service.pb.go and b/session/service.pb.go differ diff --git a/session/service.proto b/session/service.proto index 4b37aafb..9b0c65ee 100644 --- a/session/service.proto +++ b/session/service.proto @@ -3,6 +3,8 @@ package session; option go_package = "github.com/nspcc-dev/neofs-proto/session"; import "session/types.proto"; +import "service/meta.proto"; +import "service/verify.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; option (gogoproto.stable_marshaler_all) = true; @@ -34,6 +36,8 @@ message CreateRequest { // Signed Init message response (Unsigned) from server with user private key session.Token Signed = 2; } + service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; } message CreateResponse { diff --git a/state/service.pb.go b/state/service.pb.go index a3684101..8e66a2f8 100644 Binary files a/state/service.pb.go and b/state/service.pb.go differ diff --git a/state/service.proto b/state/service.proto index 3c85d860..cb2698b8 100644 --- a/state/service.proto +++ b/state/service.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package state; option go_package = "github.com/nspcc-dev/neofs-proto/state"; +import "service/meta.proto"; +import "service/verify.proto"; import "bootstrap/types.proto"; import "github.com/gogo/protobuf/gogoproto/gogo.proto"; @@ -19,10 +21,16 @@ service Status { } // NetmapRequest message to request current node netmap -message NetmapRequest {} +message NetmapRequest { + service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; +} // MetricsRequest message to request node metrics -message MetricsRequest {} +message MetricsRequest { + service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; +} // MetricsResponse contains [][]byte, // every []byte is marshaled MetricFamily proto message @@ -32,7 +40,10 @@ message MetricsResponse { } // HealthRequest message to check current state -message HealthRequest {} +message HealthRequest { + service.RequestMetaHeader Meta = 98 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; + service.RequestVerificationHeader Verify = 99 [(gogoproto.embed) = true, (gogoproto.nullable) = false]; +} // HealthResponse message with current state message HealthResponse {