diff --git a/pkg/client/accounting.go b/pkg/client/accounting.go index 0b553f2..a0cdf4b 100644 --- a/pkg/client/accounting.go +++ b/pkg/client/accounting.go @@ -29,13 +29,14 @@ func (c Client) GetBalance(ctx context.Context, owner *owner.ID, opts ...CallOpt case 2: return c.getBalanceV2(ctx, owner, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) getBalanceV2(ctx context.Context, owner *owner.ID, opts ...CallOption) (*accounting.Decimal, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -71,7 +72,7 @@ func (c Client) getBalanceV2(ctx context.Context, owner *owner.ID, opts ...CallO return accounting.NewDecimalFromV2(resp.GetBody().GetBalance()), nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -92,7 +93,7 @@ func v2AccountingClientFromOptions(opts *clientOptions) (cli *v2accounting.Clien ) default: - return nil, errors.New("lack of sdk client options to create accounting client") + return nil, errOptionsLack("Accounting") } // check if client correct and save in cache diff --git a/pkg/client/client.go b/pkg/client/client.go index 9b73fa0..94770d4 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -33,12 +33,11 @@ const ( GRPC ) -var ( - unsupportedProtocolErr = errors.New("unsupported transport protocol") -) +var errUnsupportedProtocol = errors.New("unsupported transport protocol") -func New(key *ecdsa.PrivateKey, opts ...ClientOption) (*Client, error) { +func New(key *ecdsa.PrivateKey, opts ...Option) (*Client, error) { clientOptions := defaultClientOptions() + for i := range opts { opts[i].apply(clientOptions) } diff --git a/pkg/client/container.go b/pkg/client/container.go index 5857037..fff2e92 100644 --- a/pkg/client/container.go +++ b/pkg/client/container.go @@ -18,6 +18,8 @@ type delContainerSignWrapper struct { body *v2container.DeleteRequestBody } +var errNilReponseBody = errors.New("response body is nil") + func (c delContainerSignWrapper) ReadSignedData(bytes []byte) ([]byte, error) { return c.body.GetContainerID().GetValue(), nil } @@ -31,7 +33,7 @@ func (c Client) PutContainer(ctx context.Context, cnr *container.Container, opts case 2: return c.putContainerV2(ctx, cnr, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -40,7 +42,7 @@ func (c Client) GetContainer(ctx context.Context, id *container.ID, opts ...Call case 2: return c.getContainerV2(ctx, id, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -49,7 +51,7 @@ func (c Client) ListContainers(ctx context.Context, owner *owner.ID, opts ...Cal case 2: return c.listContainerV2(ctx, owner, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -70,7 +72,7 @@ func (c Client) DeleteContainer(ctx context.Context, id *container.ID, opts ...C case 2: return c.delContainerV2(ctx, id, opts...) default: - return unsupportedProtocolErr + return errUnsupportedProtocol } } @@ -79,7 +81,7 @@ func (c Client) GetEACL(ctx context.Context, id *container.ID, opts ...CallOptio case 2: return c.getEACLV2(ctx, id, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -88,13 +90,14 @@ func (c Client) SetEACL(ctx context.Context, eacl *eacl.Table, opts ...CallOptio case 2: return c.setEACLV2(ctx, eacl, opts...) default: - return unsupportedProtocolErr + return errUnsupportedProtocol } } func (c Client) putContainerV2(ctx context.Context, cnr *container.Container, opts ...CallOption) (*container.ID, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -120,6 +123,7 @@ func (c Client) putContainerV2(ctx context.Context, cnr *container.Container, op // sign container signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetContainer()} + err := signature.SignDataWithHandler(c.key, signWrapper, func(key []byte, sig []byte) { containerSignature := new(refs.Signature) containerSignature.SetKey(key) @@ -158,13 +162,14 @@ func (c Client) putContainerV2(ctx context.Context, cnr *container.Container, op return container.NewIDFromV2(resp.GetBody().GetContainerID()), nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) getContainerV2(ctx context.Context, id *container.ID, opts ...CallOption) (*container.Container, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -200,13 +205,14 @@ func (c Client) getContainerV2(ctx context.Context, id *container.ID, opts ...Ca return container.NewContainerFromV2(resp.GetBody().GetContainer()), nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) listContainerV2(ctx context.Context, owner *owner.ID, opts ...CallOption) ([]*container.ID, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -247,13 +253,14 @@ func (c Client) listContainerV2(ctx context.Context, owner *owner.ID, opts ...Ca return result, nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) delContainerV2(ctx context.Context, id *container.ID, opts ...CallOption) error { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -305,13 +312,14 @@ func (c Client) delContainerV2(ctx context.Context, id *container.ID, opts ...Ca return nil default: - return unsupportedProtocolErr + return errUnsupportedProtocol } } func (c Client) getEACLV2(ctx context.Context, id *container.ID, opts ...CallOption) (*eacl.Table, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -347,7 +355,7 @@ func (c Client) getEACLV2(ctx context.Context, id *container.ID, opts ...CallOpt body := resp.GetBody() if body == nil { - return nil, errors.New("response body is nil") + return nil, errNilReponseBody } if err := signature.VerifyDataWithSource( @@ -367,13 +375,14 @@ func (c Client) getEACLV2(ctx context.Context, id *container.ID, opts ...CallOpt return result, nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) setEACLV2(ctx context.Context, eacl *eacl.Table, opts ...CallOption) error { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -383,6 +392,7 @@ func (c Client) setEACLV2(ctx context.Context, eacl *eacl.Table, opts ...CallOpt reqBody.GetEACL().SetVersion(c.remoteNode.Version.ToV2()) signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetEACL()} + err := signature.SignDataWithHandler(c.key, signWrapper, func(key []byte, sig []byte) { eaclSignature := new(refs.Signature) eaclSignature.SetKey(key) @@ -421,7 +431,7 @@ func (c Client) setEACLV2(ctx context.Context, eacl *eacl.Table, opts ...CallOpt return nil default: - return unsupportedProtocolErr + return errUnsupportedProtocol } } @@ -442,7 +452,7 @@ func v2ContainerClientFromOptions(opts *clientOptions) (cli *v2container.Client, ) default: - return nil, errors.New("lack of sdk client options to create container client") + return nil, errOptionsLack("Container") } // check if client correct and save in cache diff --git a/pkg/client/netmap.go b/pkg/client/netmap.go index 81ed41b..f4b0b09 100644 --- a/pkg/client/netmap.go +++ b/pkg/client/netmap.go @@ -23,7 +23,7 @@ func (c Client) EndpointInfo(ctx context.Context, opts ...CallOption) (*netmap.N return netmap.NewNodeInfoFromV2(resp.GetBody().GetNodeInfo()), nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -38,13 +38,14 @@ func (c Client) Epoch(ctx context.Context, opts ...CallOption) (uint64, error) { return resp.GetMetaHeader().GetEpoch(), nil default: - return 0, unsupportedProtocolErr + return 0, errUnsupportedProtocol } } func (c Client) endpointInfoV2(ctx context.Context, opts ...CallOption) (*v2netmap.LocalNodeInfoResponse, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -79,7 +80,7 @@ func (c Client) endpointInfoV2(ctx context.Context, opts ...CallOption) (*v2netm return resp, nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -100,7 +101,7 @@ func v2NetmapClientFromOptions(opts *clientOptions) (cli *v2netmap.Client, err e ) default: - return nil, errors.New("lack of sdk client options to create netmap client") + return nil, errOptionsLack("Netmap") } // check if client correct and save in cache diff --git a/pkg/client/object.go b/pkg/client/object.go index 197fd93..87842c4 100644 --- a/pkg/client/object.go +++ b/pkg/client/object.go @@ -89,6 +89,8 @@ const TZSize = 64 const searchQueryVersion uint32 = 1 +var errNilObjectPart = errors.New("received nil object part") + func rangesToV2(rs []*object.Range) []*v2object.Range { r2 := make([]*v2object.Range, 0, len(rs)) @@ -148,7 +150,7 @@ func (c *Client) PutObject(ctx context.Context, p *PutObjectParams, opts ...Call case 2: return c.putObjectV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -191,6 +193,7 @@ func (c *Client) putObjectV2(ctx context.Context, p *PutObjectParams, opts ...Ca }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // initialize init part @@ -268,7 +271,7 @@ func (c *Client) DeleteObject(ctx context.Context, p *DeleteObjectParams, opts . case 2: return c.deleteObjectV2(ctx, p, opts...) default: - return unsupportedProtocolErr + return errUnsupportedProtocol } } @@ -302,6 +305,7 @@ func (c *Client) deleteObjectV2(ctx context.Context, p *DeleteObjectParams, opts }); err != nil { return errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -348,7 +352,7 @@ func (c *Client) GetObject(ctx context.Context, p *GetObjectParams, opts ...Call case 2: return c.getObjectV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -382,6 +386,7 @@ func (c *Client) getObjectV2(ctx context.Context, p *GetObjectParams, opts ...Ca }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -421,7 +426,7 @@ func (c *Client) getObjectV2(ctx context.Context, p *GetObjectParams, opts ...Ca switch v := resp.GetBody().GetObjectPart().(type) { case nil: - return nil, errors.New("received nil object part") + return nil, errNilObjectPart case *v2object.GetObjectPartInit: obj.SetObjectID(v.GetObjectID()) obj.SetSignature(v.GetSignature()) @@ -481,7 +486,7 @@ func (c *Client) GetObjectHeader(ctx context.Context, p *ObjectHeaderParams, opt case 2: return c.getObjectHeaderV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -515,6 +520,7 @@ func (c *Client) getObjectHeaderV2(ctx context.Context, p *ObjectHeaderParams, o }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -541,7 +547,7 @@ func (c *Client) getObjectHeaderV2(ctx context.Context, p *ObjectHeaderParams, o switch v := resp.GetBody().GetHeaderPart().(type) { case nil: - return nil, errors.New("received nil object header part") + return nil, errNilObjectPart case *v2object.GetHeaderPartShort: if !p.short { return nil, errors.Errorf("wrong header part type: expected %T, received %T", @@ -566,8 +572,9 @@ func (c *Client) getObjectHeaderV2(ctx context.Context, p *ObjectHeaderParams, o hdrWithSig := v.GetHeaderWithSignature() if hdrWithSig == nil { - return nil, errors.New("got nil instead of header with signature") + return nil, errNilObjectPart } + hdr = hdrWithSig.GetHeader() if err := signer.VerifyDataWithSource( @@ -626,7 +633,7 @@ func (c *Client) ObjectPayloadRangeData(ctx context.Context, p *RangeDataParams, case 2: return c.objectPayloadRangeV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -660,6 +667,7 @@ func (c *Client) objectPayloadRangeV2(ctx context.Context, p *RangeDataParams, o }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -768,7 +776,7 @@ func (c *Client) objectPayloadRangeHash(ctx context.Context, p *RangeChecksumPar case 2: return c.objectPayloadRangeHashV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -802,6 +810,7 @@ func (c *Client) objectPayloadRangeHashV2(ctx context.Context, p *RangeChecksumP }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -900,7 +909,7 @@ func (c *Client) SearchObject(ctx context.Context, p *SearchObjectParams, opts . case 2: return c.searchObjectV2(ctx, p, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -937,6 +946,7 @@ func (c *Client) searchObjectV2(ctx context.Context, p *SearchObjectParams, opts }); err != nil { return nil, errors.Wrap(err, "could not sign session token") } + req.SetMetaHeader(meta) // fill body fields @@ -1009,7 +1019,7 @@ func v2ObjectClient(proto TransportProtocol, opts *clientOptions) (*v2object.Cli return opts.grpcOpts.objectClientV2, err default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -1042,6 +1052,7 @@ func (c Client) attachV2SessionToken(opts callOptions, hdr *v2session.RequestMet body.SetLifetime(lt) signWrapper := signature.StableMarshalerWrapper{SM: token.GetBody()} + err := signer.SignDataWithHandler(c.key, signWrapper, func(key []byte, sig []byte) { sessionTokenSignature := new(v2refs.Signature) sessionTokenSignature.SetKey(key) diff --git a/pkg/client/opts.go b/pkg/client/opts.go index 4404ab6..e4dd299 100644 --- a/pkg/client/opts.go +++ b/pkg/client/opts.go @@ -1,6 +1,8 @@ package client import ( + "fmt" + "github.com/nspcc-dev/neofs-api-go/pkg" "github.com/nspcc-dev/neofs-api-go/pkg/token" v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting" @@ -17,7 +19,7 @@ type ( apply(*callOptions) } - ClientOption interface { + Option interface { apply(*clientOptions) } @@ -54,6 +56,12 @@ type ( } ) +type errOptionsLack string + +func (e errOptionsLack) Error() string { + return fmt.Sprintf("lack of sdk client options to create %s client", string(e)) +} + func (c Client) defaultCallOptions() callOptions { return callOptions{ ttl: 2, @@ -149,13 +157,13 @@ func newFuncClientOption(f func(option *clientOptions)) *funcClientOption { } } -func WithAddress(addr string) ClientOption { +func WithAddress(addr string) Option { return newFuncClientOption(func(option *clientOptions) { option.addr = addr }) } -func WithGRPCConnection(grpcConn *grpc.ClientConn) ClientOption { +func WithGRPCConnection(grpcConn *grpc.ClientConn) Option { return newFuncClientOption(func(option *clientOptions) { option.grpcOpts.conn = grpcConn }) diff --git a/pkg/client/session.go b/pkg/client/session.go index e845b0d..c45f784 100644 --- a/pkg/client/session.go +++ b/pkg/client/session.go @@ -11,18 +11,21 @@ import ( "github.com/pkg/errors" ) +var errMalformedResponseBody = errors.New("malformed response body") + func (c Client) CreateSession(ctx context.Context, expiration uint64, opts ...CallOption) (*token.SessionToken, error) { switch c.remoteNode.Version.Major() { case 2: return c.createSessionV2(ctx, expiration, opts...) default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } func (c Client) createSessionV2(ctx context.Context, expiration uint64, opts ...CallOption) (*token.SessionToken, error) { // apply all available options callOptions := c.defaultCallOptions() + for i := range opts { opts[i].apply(&callOptions) } @@ -67,7 +70,7 @@ func (c Client) createSessionV2(ctx context.Context, expiration uint64, opts ... body := resp.GetBody() if body == nil { - return nil, errors.New("malformed response body") + return nil, errMalformedResponseBody } sessionToken := token.NewSessionToken() @@ -77,7 +80,7 @@ func (c Client) createSessionV2(ctx context.Context, expiration uint64, opts ... return sessionToken, nil default: - return nil, unsupportedProtocolErr + return nil, errUnsupportedProtocol } } @@ -98,7 +101,7 @@ func v2SessionClientFromOptions(opts *clientOptions) (cli *v2session.Client, err ) default: - return nil, errors.New("lack of sdk client options to create session client") + return nil, errOptionsLack("Session") } // check if client correct and save in cache