forked from TrueCloudLab/frostfs-api-go
Update develop branch
This commit is contained in:
parent
5d4759a6c6
commit
24e5497b1d
34 changed files with 642 additions and 324 deletions
2
Makefile
2
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
|
||||
|
|
|
@ -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()
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
Binary file not shown.
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
90
service/meta.go
Normal file
90
service/meta.go
Normal file
|
@ -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
|
||||
}
|
BIN
service/meta.pb.go
Normal file
BIN
service/meta.pb.go
Normal file
Binary file not shown.
12
service/meta.proto
Normal file
12
service/meta.proto
Normal file
|
@ -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;
|
||||
}
|
70
service/meta_test.go
Normal file
70
service/meta_test.go
Normal file
|
@ -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())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNodeRole_String(t *testing.T) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
179
service/verify.go
Normal file
179
service/verify.go
Normal file
|
@ -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
|
||||
}
|
BIN
service/verify.pb.go
Normal file
BIN
service/verify.pb.go
Normal file
Binary file not shown.
20
service/verify.proto
Normal file
20
service/verify.proto
Normal file
|
@ -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;
|
||||
}
|
106
service/verify_test.go
Normal file
106
service/verify_test.go
Normal file
|
@ -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())
|
||||
}
|
||||
}
|
BIN
service/verify_test.pb.go
Normal file
BIN
service/verify_test.pb.go
Normal file
Binary file not shown.
17
service/verify_test.proto
Normal file
17
service/verify_test.proto
Normal file
|
@ -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];
|
||||
}
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
Binary file not shown.
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue