diff --git a/cmd/neofs-cli/modules/request/container.go b/cmd/neofs-cli/modules/request/container.go index a40686c2e2..fafbde3426 100644 --- a/cmd/neofs-cli/modules/request/container.go +++ b/cmd/neofs-cli/modules/request/container.go @@ -161,13 +161,7 @@ func createContainer(cmd *cobra.Command, args []string) error { return fmt.Errorf("transport failure: %w", err) } - cmd.Println("Response received. Checking signatures...") - - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return fmt.Errorf("failed to verify response signatures: %w", err) - } - - cmd.Println("Signatures are valid. Checking status...") + cmd.Println("Response received. Checking status...") if err := apistatus.ToError(resp.GetMetaHeader().GetStatus()); err != nil { return fmt.Errorf("status failure: %w", err) @@ -210,13 +204,7 @@ func createContainer(cmd *cobra.Command, args []string) error { return fmt.Errorf("transport failure: %w", err) } - cmd.Println("Response received. Checking signatures...") - - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return fmt.Errorf("failed to verify response signatures: %w", err) - } - - cmd.Println("Signatures are valid. Checking status...") + cmd.Println("Response received. Checking status...") if err := apistatus.ToError(resp.GetMetaHeader().GetStatus()); err == nil { cmd.Println("Status OK. Operation succeeded.") diff --git a/cmd/neofs-node/container.go b/cmd/neofs-node/container.go index 20fa376d74..fc2f3bdcfb 100644 --- a/cmd/neofs-node/container.go +++ b/cmd/neofs-node/container.go @@ -511,7 +511,7 @@ func (c *usedSpaceService) NumberOfAddresses() int { return c.cfg.addressNum() } -func (c *usedSpaceService) makeResponse(body *protocontainer.AnnounceUsedSpaceResponse_Body, st *protostatus.Status) (*protocontainer.AnnounceUsedSpaceResponse, error) { +func (c *usedSpaceService) makeResponse(body *protocontainer.AnnounceUsedSpaceResponse_Body, st *protostatus.Status, req *protocontainer.AnnounceUsedSpaceRequest) (*protocontainer.AnnounceUsedSpaceResponse, error) { resp := &protocontainer.AnnounceUsedSpaceResponse{ Body: body, MetaHeader: &protosession.ResponseMetaHeader{ @@ -520,17 +520,17 @@ func (c *usedSpaceService) makeResponse(body *protocontainer.AnnounceUsedSpaceRe Status: st, }, } - resp.VerifyHeader = util.SignResponse(&c.cfg.key.PrivateKey, resp) + resp.VerifyHeader = util.SignResponse(&c.cfg.key.PrivateKey, resp, req) return resp, nil } -func (c *usedSpaceService) makeStatusResponse(err error) (*protocontainer.AnnounceUsedSpaceResponse, error) { - return c.makeResponse(nil, util.ToStatus(err)) +func (c *usedSpaceService) makeStatusResponse(err error, req *protocontainer.AnnounceUsedSpaceRequest) (*protocontainer.AnnounceUsedSpaceResponse, error) { + return c.makeResponse(nil, util.ToStatus(err), req) } func (c *usedSpaceService) AnnounceUsedSpace(ctx context.Context, req *protocontainer.AnnounceUsedSpaceRequest) (*protocontainer.AnnounceUsedSpaceResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return c.makeStatusResponse(err) + return c.makeStatusResponse(err, req) } var passedRoute []loadroute.ServerInfo @@ -549,7 +549,7 @@ func (c *usedSpaceService) AnnounceUsedSpace(ctx context.Context, req *protocont w, err := c.loadWriterProvider.InitWriter(loadroute.NewRouteContext(ctx, passedRoute)) if err != nil { - return c.makeStatusResponse(fmt.Errorf("could not initialize container's used space writer: %w", err)) + return c.makeStatusResponse(fmt.Errorf("could not initialize container's used space writer: %w", err), req) } var est containerSDK.SizeEstimation @@ -557,15 +557,15 @@ func (c *usedSpaceService) AnnounceUsedSpace(ctx context.Context, req *protocont for _, a := range req.GetBody().GetAnnouncements() { err = est.FromProtoMessage(a) if err != nil { - return c.makeStatusResponse(fmt.Errorf("invalid size announcement: %w", err)) + return c.makeStatusResponse(fmt.Errorf("invalid size announcement: %w", err), req) } if err := c.processLoadValue(ctx, est, passedRoute, w); err != nil { - return c.makeStatusResponse(err) + return c.makeStatusResponse(err, req) } } - return c.makeResponse(nil, util.StatusOK) + return c.makeResponse(nil, util.StatusOK, req) } var errNodeOutsideContainer = errors.New("node outside the container") diff --git a/cmd/neofs-node/reputation.go b/cmd/neofs-node/reputation.go index cfc5289d36..ccaf5b3156 100644 --- a/cmd/neofs-node/reputation.go +++ b/cmd/neofs-node/reputation.go @@ -263,17 +263,17 @@ func (s *reputationServer) makeResponseMetaHeader(st *protostatus.Status) *proto } } -func (s *reputationServer) makeLocalResponse(err error) (*protoreputation.AnnounceLocalTrustResponse, error) { +func (s *reputationServer) makeLocalResponse(err error, req *protoreputation.AnnounceLocalTrustRequest) (*protoreputation.AnnounceLocalTrustResponse, error) { resp := &protoreputation.AnnounceLocalTrustResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), } - resp.VerifyHeader = util.SignResponse(&s.key.PrivateKey, resp) + resp.VerifyHeader = util.SignResponse(&s.key.PrivateKey, resp, req) return resp, nil } func (s *reputationServer) AnnounceLocalTrust(ctx context.Context, req *protoreputation.AnnounceLocalTrustRequest) (*protoreputation.AnnounceLocalTrustResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeLocalResponse(err) + return s.makeLocalResponse(err, req) } passedRoute := reverseRoute(req.GetVerifyHeader()) @@ -288,30 +288,30 @@ func (s *reputationServer) AnnounceLocalTrust(ctx context.Context, req *protorep w, err := s.localRouter.InitWriter(reputationrouter.NewRouteContext(eCtx, passedRoute)) if err != nil { - return s.makeLocalResponse(fmt.Errorf("could not initialize local trust writer: %w", err)) + return s.makeLocalResponse(fmt.Errorf("could not initialize local trust writer: %w", err), req) } for _, trust := range body.GetTrusts() { err = s.processLocalTrust(body.GetEpoch(), apiToLocalTrust(trust, passedRoute[0].PublicKey()), passedRoute, w) if err != nil { - return s.makeLocalResponse(fmt.Errorf("could not write one of local trusts: %w", err)) + return s.makeLocalResponse(fmt.Errorf("could not write one of local trusts: %w", err), req) } } - return s.makeLocalResponse(util.StatusOKErr) + return s.makeLocalResponse(util.StatusOKErr, req) } -func (s *reputationServer) makeIntermediateResponse(err error) (*protoreputation.AnnounceIntermediateResultResponse, error) { +func (s *reputationServer) makeIntermediateResponse(err error, req *protoreputation.AnnounceIntermediateResultRequest) (*protoreputation.AnnounceIntermediateResultResponse, error) { resp := &protoreputation.AnnounceIntermediateResultResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), } - resp.VerifyHeader = util.SignResponse(&s.key.PrivateKey, resp) + resp.VerifyHeader = util.SignResponse(&s.key.PrivateKey, resp, req) return resp, nil } func (s *reputationServer) AnnounceIntermediateResult(ctx context.Context, req *protoreputation.AnnounceIntermediateResultRequest) (*protoreputation.AnnounceIntermediateResultResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeIntermediateResponse(err) + return s.makeIntermediateResponse(err, req) } passedRoute := reverseRoute(req.GetVerifyHeader()) @@ -323,7 +323,7 @@ func (s *reputationServer) AnnounceIntermediateResult(ctx context.Context, req * w, err := s.intermediateRouter.InitWriter(reputationrouter.NewRouteContext(eiCtx, passedRoute)) if err != nil { - return s.makeIntermediateResponse(fmt.Errorf("could not initialize trust writer: %w", err)) + return s.makeIntermediateResponse(fmt.Errorf("could not initialize trust writer: %w", err), req) } v2Trust := body.GetTrust() @@ -332,10 +332,10 @@ func (s *reputationServer) AnnounceIntermediateResult(ctx context.Context, req * err = w.Write(trust) if err != nil { - return s.makeIntermediateResponse(fmt.Errorf("could not write trust: %w", err)) + return s.makeIntermediateResponse(fmt.Errorf("could not write trust: %w", err), req) } - return s.makeIntermediateResponse(util.StatusOKErr) + return s.makeIntermediateResponse(util.StatusOKErr, req) } func (s *reputationServer) processLocalTrust(epoch uint64, t reputation.Trust, diff --git a/go.mod b/go.mod index 9dd07250ce..eb9cdc033f 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/nspcc-dev/neo-go v0.110.0 github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea github.com/nspcc-dev/neofs-contract v0.23.0 - github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250610144537-4b8bd696a7eb + github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250611171242-421f0237ff94 github.com/nspcc-dev/tzhash v1.8.2 github.com/olekukonko/tablewriter v0.0.5 github.com/panjf2000/ants/v2 v2.9.0 diff --git a/go.sum b/go.sum index 260877e114..ef5e3cf713 100644 --- a/go.sum +++ b/go.sum @@ -201,8 +201,8 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y= github.com/nspcc-dev/neofs-contract v0.23.0 h1:F5ciU0wPqSbycPY8qOtb4PvgnSZBNQ5Jp9tdeVSKu4o= github.com/nspcc-dev/neofs-contract v0.23.0/go.mod h1:it6Su92UvEFQDsMOfDIXapLu0j5TQSOvkS2YdUlPdgo= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250610144537-4b8bd696a7eb h1:aQ6W8/8SIvcJwH1QF+NuwB8Uvt6LYFCOcRHLgynejeA= -github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250610144537-4b8bd696a7eb/go.mod h1:j/NUu5iOGFkOVYM42XoC1X9DZD0/y89Pws++w5vxtQk= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250611171242-421f0237ff94 h1:W7JPuX/tclgcX2VF8zECEpCOn68diUJiJKl74731nb8= +github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.13.0.20250611171242-421f0237ff94/go.mod h1:j/NUu5iOGFkOVYM42XoC1X9DZD0/y89Pws++w5vxtQk= github.com/nspcc-dev/rfc6979 v0.2.3 h1:QNVykGZ3XjFwM/88rGfV3oj4rKNBy+nYI6jM7q19hDI= github.com/nspcc-dev/rfc6979 v0.2.3/go.mod h1:q3sCL1Ed7homjqYK8KmFSzEmm+7Ngyo7PePbZanhaDE= github.com/nspcc-dev/tzhash v1.8.2 h1:ebRCbPoEuoqrhC6sSZmrT/jI3h1SzCWakxxV6gp5QAg= diff --git a/pkg/core/client/util.go b/pkg/core/client/util.go index a4c3a1602a..e8f0b41fe3 100644 --- a/pkg/core/client/util.go +++ b/pkg/core/client/util.go @@ -1,11 +1,9 @@ package client import ( - "bytes" "fmt" "github.com/nspcc-dev/neofs-node/pkg/network" - "github.com/nspcc-dev/neofs-sdk-go/client" ) // NodeInfoFromRawNetmapElement fills NodeInfo structure from the interface of raw netmap member's descriptor. @@ -28,15 +26,3 @@ func NodeInfoFromRawNetmapElement(dst *NodeInfo, info interface { return nil } - -// AssertKeyResponseCallback returns client response callback which checks if the response was signed by the expected key. -// Returns ErrWrongPublicKey in case of key mismatch. -func AssertKeyResponseCallback(expectedKey []byte) func(client.ResponseMetaInfo) error { - return func(info client.ResponseMetaInfo) error { - if !bytes.Equal(info.ResponderKey(), expectedKey) { - return ErrWrongPublicKey - } - - return nil - } -} diff --git a/pkg/network/cache/client.go b/pkg/network/cache/client.go index f0d56e605a..c3e1494cbe 100644 --- a/pkg/network/cache/client.go +++ b/pkg/network/cache/client.go @@ -5,7 +5,6 @@ import ( "time" clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client" - "github.com/nspcc-dev/neofs-sdk-go/client" "go.uber.org/zap" ) @@ -25,7 +24,6 @@ type ( DialTimeout time.Duration StreamTimeout time.Duration ReconnectTimeout time.Duration - ResponseCallback func(client.ResponseMetaInfo) error Buffers *sync.Pool Logger *zap.Logger } @@ -65,7 +63,6 @@ func (c *ClientCache) Get(info clientcore.NodeInfo) (clientcore.Client, error) { } newClientOpts := c.opts - newClientOpts.ResponseCallback = clientcore.AssertKeyResponseCallback(info.PublicKey()) cli := newMultiClient(netAddr, newClientOpts) c.clients[cacheKey] = cli diff --git a/pkg/network/cache/multi.go b/pkg/network/cache/multi.go index 2eec677d59..a5c74904e3 100644 --- a/pkg/network/cache/multi.go +++ b/pkg/network/cache/multi.go @@ -75,10 +75,6 @@ func (x *multiClient) createForAddress(addr network.Address) (*client.Client, er prmDial.SetStreamTimeout(x.opts.StreamTimeout) } - if x.opts.ResponseCallback != nil { - prmInit.SetResponseInfoCallback(x.opts.ResponseCallback) - } - c, err := client.New(prmInit) if err != nil { return nil, fmt.Errorf("can't create SDK client: %w", err) diff --git a/pkg/services/accounting/server.go b/pkg/services/accounting/server.go index 895ca47d94..1d52beb672 100644 --- a/pkg/services/accounting/server.go +++ b/pkg/services/accounting/server.go @@ -46,7 +46,7 @@ func New(s *ecdsa.PrivateKey, net netmap.State, c BalanceContract) protoaccounti } } -func (s *server) makeBalanceResponse(body *protoaccounting.BalanceResponse_Body, st *protostatus.Status) (*protoaccounting.BalanceResponse, error) { +func (s *server) makeBalanceResponse(body *protoaccounting.BalanceResponse_Body, st *protostatus.Status, req *protoaccounting.BalanceRequest) (*protoaccounting.BalanceResponse, error) { resp := &protoaccounting.BalanceResponse{ Body: body, MetaHeader: &protosession.ResponseMetaHeader{ @@ -55,41 +55,41 @@ func (s *server) makeBalanceResponse(body *protoaccounting.BalanceResponse_Body, Status: st, }, } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedBalanceResponse(err error) (*protoaccounting.BalanceResponse, error) { - return s.makeBalanceResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedBalanceResponse(err error, req *protoaccounting.BalanceRequest) (*protoaccounting.BalanceResponse, error) { + return s.makeBalanceResponse(nil, util.ToStatus(err), req) } // Balance gets current balance of the requested user using underlying // [BalanceContract] and returns result in the response. func (s *server) Balance(_ context.Context, req *protoaccounting.BalanceRequest) (*protoaccounting.BalanceResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedBalanceResponse(err) + return s.makeFailedBalanceResponse(err, nil) } mUsr := req.GetBody().GetOwnerId() if mUsr == nil { - return s.makeFailedBalanceResponse(errors.New("missing account")) + return s.makeFailedBalanceResponse(errors.New("missing account"), req) } var id user.ID if err := id.FromProtoMessage(mUsr); err != nil { - return s.makeFailedBalanceResponse(fmt.Errorf("invalid account: %w", err)) + return s.makeFailedBalanceResponse(fmt.Errorf("invalid account: %w", err), req) } bal, err := s.contract.BalanceOf(id) if err != nil { - return s.makeFailedBalanceResponse(err) + return s.makeFailedBalanceResponse(err, req) } ds, err := s.contract.Decimals() if err != nil { - return s.makeFailedBalanceResponse(err) + return s.makeFailedBalanceResponse(err, req) } body := &protoaccounting.BalanceResponse_Body{ Balance: &protoaccounting.Decimal{Value: bal.Int64(), Precision: ds}, } - return s.makeBalanceResponse(body, util.StatusOK) + return s.makeBalanceResponse(body, util.StatusOK, req) } diff --git a/pkg/services/container/server.go b/pkg/services/container/server.go index 1d41549b7b..2791eadf01 100644 --- a/pkg/services/container/server.go +++ b/pkg/services/container/server.go @@ -173,17 +173,17 @@ func (s *server) checkSessionIssuer(id cid.ID, issuer user.ID) error { return nil } -func (s *server) makePutResponse(body *protocontainer.PutResponse_Body, st *protostatus.Status) (*protocontainer.PutResponse, error) { +func (s *server) makePutResponse(body *protocontainer.PutResponse_Body, st *protostatus.Status, req *protocontainer.PutRequest) (*protocontainer.PutResponse, error) { resp := &protocontainer.PutResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedPutResponse(err error) (*protocontainer.PutResponse, error) { - return s.makePutResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedPutResponse(err error, req *protocontainer.PutRequest) (*protocontainer.PutResponse, error) { + return s.makePutResponse(nil, util.ToStatus(err), req) } const ( @@ -239,52 +239,52 @@ func verifyStoragePolicy(policy *protonetmap.PlacementPolicy) error { // to check request status in the response. func (s *server) Put(_ context.Context, req *protocontainer.PutRequest) (*protocontainer.PutResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedPutResponse(err) + return s.makeFailedPutResponse(err, req) } reqBody := req.GetBody() mSig := reqBody.GetSignature() if mSig == nil { - return s.makeFailedPutResponse(errors.New("missing container signature")) + return s.makeFailedPutResponse(errors.New("missing container signature"), req) } mCnr := reqBody.GetContainer() if mCnr == nil { - return s.makeFailedPutResponse(errors.New("missing container")) + return s.makeFailedPutResponse(errors.New("missing container"), req) } if mCnr.PlacementPolicy == nil { - return s.makeFailedPutResponse(errors.New("missing storage policy")) + return s.makeFailedPutResponse(errors.New("missing storage policy"), req) } if err := verifyStoragePolicy(mCnr.PlacementPolicy); err != nil { - return s.makeFailedPutResponse(fmt.Errorf("invalid storage policy: %w", err)) + return s.makeFailedPutResponse(fmt.Errorf("invalid storage policy: %w", err), req) } var cnr container.Container if err := cnr.FromProtoMessage(mCnr); err != nil { - return s.makeFailedPutResponse(fmt.Errorf("invalid container: %w", err)) + return s.makeFailedPutResponse(fmt.Errorf("invalid container: %w", err), req) } st, err := s.getVerifiedSessionToken(req) if err != nil { - return s.makeFailedPutResponse(fmt.Errorf("verify session token: %w", err)) + return s.makeFailedPutResponse(fmt.Errorf("verify session token: %w", err), req) } id, err := s.contract.Put(cnr, mSig.Key, mSig.Sign, st) if err != nil { - return s.makeFailedPutResponse(err) + return s.makeFailedPutResponse(err, req) } respBody := &protocontainer.PutResponse_Body{ ContainerId: id.ProtoMessage(), } - return s.makePutResponse(respBody, util.StatusOK) + return s.makePutResponse(respBody, util.StatusOK, req) } -func (s *server) makeDeleteResponse(err error) (*protocontainer.DeleteResponse, error) { +func (s *server) makeDeleteResponse(err error, req *protocontainer.DeleteRequest) (*protocontainer.DeleteResponse, error) { resp := &protocontainer.DeleteResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } @@ -292,122 +292,122 @@ func (s *server) makeDeleteResponse(err error) (*protocontainer.DeleteResponse, // further processing. If session token is attached, it's verified. func (s *server) Delete(_ context.Context, req *protocontainer.DeleteRequest) (*protocontainer.DeleteResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeDeleteResponse(err) + return s.makeDeleteResponse(err, req) } reqBody := req.GetBody() mSig := reqBody.GetSignature() if mSig == nil { - return s.makeDeleteResponse(errors.New("missing ID signature")) + return s.makeDeleteResponse(errors.New("missing ID signature"), req) } mID := reqBody.GetContainerId() if mID == nil { - return s.makeDeleteResponse(errors.New("missing ID")) + return s.makeDeleteResponse(errors.New("missing ID"), req) } var id cid.ID if err := id.FromProtoMessage(mID); err != nil { - return s.makeDeleteResponse(fmt.Errorf("invalid ID: %w", err)) + return s.makeDeleteResponse(fmt.Errorf("invalid ID: %w", err), req) } st, err := s.getVerifiedSessionToken(req) if err != nil { - return s.makeDeleteResponse(fmt.Errorf("verify session token: %w", err)) + return s.makeDeleteResponse(fmt.Errorf("verify session token: %w", err), req) } if st != nil { if err := s.checkSessionIssuer(id, st.Issuer()); err != nil { - return s.makeDeleteResponse(fmt.Errorf("verify session issuer: %w", err)) + return s.makeDeleteResponse(fmt.Errorf("verify session issuer: %w", err), req) } if !st.AppliedTo(id) { - return s.makeDeleteResponse(errors.New("session is not applied to requested container")) + return s.makeDeleteResponse(errors.New("session is not applied to requested container"), req) } } if err := s.contract.Delete(id, mSig.Key, mSig.Sign, st); err != nil { - return s.makeDeleteResponse(err) + return s.makeDeleteResponse(err, req) } - return s.makeDeleteResponse(util.StatusOKErr) + return s.makeDeleteResponse(util.StatusOKErr, req) } -func (s *server) makeGetResponse(body *protocontainer.GetResponse_Body, st *protostatus.Status) (*protocontainer.GetResponse, error) { +func (s *server) makeGetResponse(body *protocontainer.GetResponse_Body, st *protostatus.Status, req *protocontainer.GetRequest) (*protocontainer.GetResponse, error) { resp := &protocontainer.GetResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedGetResponse(err error) (*protocontainer.GetResponse, error) { - return s.makeGetResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedGetResponse(err error, req *protocontainer.GetRequest) (*protocontainer.GetResponse, error) { + return s.makeGetResponse(nil, util.ToStatus(err), req) } // Get requests container from the underlying [Contract] and returns it in the // response. func (s *server) Get(_ context.Context, req *protocontainer.GetRequest) (*protocontainer.GetResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedGetResponse(err) + return s.makeFailedGetResponse(err, req) } mID := req.GetBody().GetContainerId() if mID == nil { - return s.makeFailedGetResponse(errors.New("missing ID")) + return s.makeFailedGetResponse(errors.New("missing ID"), req) } var id cid.ID if err := id.FromProtoMessage(mID); err != nil { - return s.makeFailedGetResponse(fmt.Errorf("invalid ID: %w", err)) + return s.makeFailedGetResponse(fmt.Errorf("invalid ID: %w", err), req) } cnr, err := s.contract.Get(id) if err != nil { - return s.makeFailedGetResponse(err) + return s.makeFailedGetResponse(err, req) } body := &protocontainer.GetResponse_Body{ Container: cnr.ProtoMessage(), } - return s.makeGetResponse(body, nil) + return s.makeGetResponse(body, nil, req) } -func (s *server) makeListResponse(body *protocontainer.ListResponse_Body, st *protostatus.Status) (*protocontainer.ListResponse, error) { +func (s *server) makeListResponse(body *protocontainer.ListResponse_Body, st *protostatus.Status, req *protocontainer.ListRequest) (*protocontainer.ListResponse, error) { resp := &protocontainer.ListResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedListResponse(err error) (*protocontainer.ListResponse, error) { - return s.makeListResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedListResponse(err error, req *protocontainer.ListRequest) (*protocontainer.ListResponse, error) { + return s.makeListResponse(nil, util.ToStatus(err), req) } // List lists user containers from the underlying [Contract] and returns their // IDs in the response. func (s *server) List(_ context.Context, req *protocontainer.ListRequest) (*protocontainer.ListResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedListResponse(err) + return s.makeFailedListResponse(err, req) } mID := req.GetBody().GetOwnerId() if mID == nil { - return s.makeFailedListResponse(errors.New("missing user")) + return s.makeFailedListResponse(errors.New("missing user"), req) } var id user.ID if err := id.FromProtoMessage(mID); err != nil { - return s.makeFailedListResponse(fmt.Errorf("invalid user: %w", err)) + return s.makeFailedListResponse(fmt.Errorf("invalid user: %w", err), req) } cs, err := s.contract.List(id) if err != nil { - return s.makeFailedListResponse(err) + return s.makeFailedListResponse(err, req) } if len(cs) == 0 { - return s.makeListResponse(nil, util.StatusOK) + return s.makeListResponse(nil, util.StatusOK, req) } body := &protocontainer.ListResponse_Body{ @@ -416,14 +416,14 @@ func (s *server) List(_ context.Context, req *protocontainer.ListRequest) (*prot for i := range cs { body.ContainerIds[i] = cs[i].ProtoMessage() } - return s.makeListResponse(body, util.StatusOK) + return s.makeListResponse(body, util.StatusOK, req) } -func (s *server) makeSetEACLResponse(err error) (*protocontainer.SetExtendedACLResponse, error) { +func (s *server) makeSetEACLResponse(err error, req *protocontainer.SetExtendedACLRequest) (*protocontainer.SetExtendedACLResponse, error) { resp := &protocontainer.SetExtendedACLResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } @@ -431,82 +431,82 @@ func (s *server) makeSetEACLResponse(err error) (*protocontainer.SetExtendedACLR // for further processing. If session token is attached, it's verified. func (s *server) SetExtendedACL(_ context.Context, req *protocontainer.SetExtendedACLRequest) (*protocontainer.SetExtendedACLResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeSetEACLResponse(err) + return s.makeSetEACLResponse(err, req) } reqBody := req.GetBody() mSig := reqBody.GetSignature() if mSig == nil { - return s.makeSetEACLResponse(errors.New("missing eACL signature")) + return s.makeSetEACLResponse(errors.New("missing eACL signature"), req) } mEACL := reqBody.GetEacl() if mEACL == nil { - return s.makeSetEACLResponse(errors.New("missing eACL")) + return s.makeSetEACLResponse(errors.New("missing eACL"), req) } var eACL eacl.Table if err := eACL.FromProtoMessage(mEACL); err != nil { - return s.makeSetEACLResponse(fmt.Errorf("invalid eACL: %w", err)) + return s.makeSetEACLResponse(fmt.Errorf("invalid eACL: %w", err), req) } st, err := s.getVerifiedSessionToken(req) if err != nil { - return s.makeSetEACLResponse(fmt.Errorf("verify session token: %w", err)) + return s.makeSetEACLResponse(fmt.Errorf("verify session token: %w", err), req) } if st != nil { id := eACL.GetCID() if err := s.checkSessionIssuer(id, st.Issuer()); err != nil { - return s.makeSetEACLResponse(fmt.Errorf("verify session issuer: %w", err)) + return s.makeSetEACLResponse(fmt.Errorf("verify session issuer: %w", err), req) } if !st.AppliedTo(id) { - return s.makeSetEACLResponse(errors.New("session is not applied to requested container")) + return s.makeSetEACLResponse(errors.New("session is not applied to requested container"), req) } } if err := s.contract.PutEACL(eACL, mSig.Key, mSig.Sign, st); err != nil { - return s.makeSetEACLResponse(err) + return s.makeSetEACLResponse(err, req) } - return s.makeSetEACLResponse(util.StatusOKErr) + return s.makeSetEACLResponse(util.StatusOKErr, req) } -func (s *server) makeGetEACLResponse(body *protocontainer.GetExtendedACLResponse_Body, st *protostatus.Status) (*protocontainer.GetExtendedACLResponse, error) { +func (s *server) makeGetEACLResponse(body *protocontainer.GetExtendedACLResponse_Body, st *protostatus.Status, req *protocontainer.GetExtendedACLRequest) (*protocontainer.GetExtendedACLResponse, error) { resp := &protocontainer.GetExtendedACLResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedGetEACLResponse(err error) (*protocontainer.GetExtendedACLResponse, error) { - return s.makeGetEACLResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedGetEACLResponse(err error, req *protocontainer.GetExtendedACLRequest) (*protocontainer.GetExtendedACLResponse, error) { + return s.makeGetEACLResponse(nil, util.ToStatus(err), req) } // GetExtendedACL read eACL of the requested container from the underlying // [Contract] and returns the result in the response. func (s *server) GetExtendedACL(_ context.Context, req *protocontainer.GetExtendedACLRequest) (*protocontainer.GetExtendedACLResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedGetEACLResponse(err) + return s.makeFailedGetEACLResponse(err, req) } mID := req.GetBody().GetContainerId() if mID == nil { - return s.makeFailedGetEACLResponse(errors.New("missing ID")) + return s.makeFailedGetEACLResponse(errors.New("missing ID"), req) } var id cid.ID if err := id.FromProtoMessage(mID); err != nil { - return s.makeFailedGetEACLResponse(fmt.Errorf("invalid ID: %w", err)) + return s.makeFailedGetEACLResponse(fmt.Errorf("invalid ID: %w", err), req) } eACL, err := s.contract.GetEACL(id) if err != nil { - return s.makeFailedGetEACLResponse(err) + return s.makeFailedGetEACLResponse(err, req) } body := &protocontainer.GetExtendedACLResponse_Body{ Eacl: eACL.ProtoMessage(), } - return s.makeGetEACLResponse(body, util.StatusOK) + return s.makeGetEACLResponse(body, util.StatusOK, req) } diff --git a/pkg/services/netmap/server.go b/pkg/services/netmap/server.go index 84184359cb..88460a160d 100644 --- a/pkg/services/netmap/server.go +++ b/pkg/services/netmap/server.go @@ -57,95 +57,95 @@ func (s *server) makeResponseMetaHeader(st *protostatus.Status) *protosession.Re } } -func (s *server) makeNodeInfoResponse(body *protonetmap.LocalNodeInfoResponse_Body, st *protostatus.Status) (*protonetmap.LocalNodeInfoResponse, error) { +func (s *server) makeNodeInfoResponse(body *protonetmap.LocalNodeInfoResponse_Body, st *protostatus.Status, req *protonetmap.LocalNodeInfoRequest) (*protonetmap.LocalNodeInfoResponse, error) { resp := &protonetmap.LocalNodeInfoResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeStatusNodeInfoResponse(err error) (*protonetmap.LocalNodeInfoResponse, error) { - return s.makeNodeInfoResponse(nil, util.ToStatus(err)) +func (s *server) makeStatusNodeInfoResponse(err error, req *protonetmap.LocalNodeInfoRequest) (*protonetmap.LocalNodeInfoResponse, error) { + return s.makeNodeInfoResponse(nil, util.ToStatus(err), req) } // LocalNodeInfo returns current state of the local node from the underlying // [NodeState]. func (s server) LocalNodeInfo(_ context.Context, req *protonetmap.LocalNodeInfoRequest) (*protonetmap.LocalNodeInfoResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeStatusNodeInfoResponse(err) + return s.makeStatusNodeInfoResponse(err, req) } n, err := s.contract.LocalNodeInfo() if err != nil { - return s.makeStatusNodeInfoResponse(err) + return s.makeStatusNodeInfoResponse(err, req) } body := &protonetmap.LocalNodeInfoResponse_Body{ Version: currentProtoVersion(), NodeInfo: n.ProtoMessage(), } - return s.makeNodeInfoResponse(body, util.StatusOK) + return s.makeNodeInfoResponse(body, util.StatusOK, req) } -func (s *server) makeNetInfoResponse(body *protonetmap.NetworkInfoResponse_Body, st *protostatus.Status) (*protonetmap.NetworkInfoResponse, error) { +func (s *server) makeNetInfoResponse(body *protonetmap.NetworkInfoResponse_Body, st *protostatus.Status, req *protonetmap.NetworkInfoRequest) (*protonetmap.NetworkInfoResponse, error) { resp := &protonetmap.NetworkInfoResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeStatusNetInfoResponse(err error) (*protonetmap.NetworkInfoResponse, error) { - return s.makeNetInfoResponse(nil, util.ToStatus(err)) +func (s *server) makeStatusNetInfoResponse(err error, req *protonetmap.NetworkInfoRequest) (*protonetmap.NetworkInfoResponse, error) { + return s.makeNetInfoResponse(nil, util.ToStatus(err), req) } // NetworkInfo returns current network configuration from the underlying // [Contract]. func (s *server) NetworkInfo(_ context.Context, req *protonetmap.NetworkInfoRequest) (*protonetmap.NetworkInfoResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeStatusNetInfoResponse(err) + return s.makeStatusNetInfoResponse(err, req) } n, err := s.contract.GetNetworkInfo() if err != nil { - return s.makeStatusNetInfoResponse(err) + return s.makeStatusNetInfoResponse(err, req) } body := &protonetmap.NetworkInfoResponse_Body{ NetworkInfo: n.ProtoMessage(), } - return s.makeNetInfoResponse(body, util.StatusOK) + return s.makeNetInfoResponse(body, util.StatusOK, req) } -func (s *server) makeNetmapResponse(body *protonetmap.NetmapSnapshotResponse_Body, st *protostatus.Status) (*protonetmap.NetmapSnapshotResponse, error) { +func (s *server) makeNetmapResponse(body *protonetmap.NetmapSnapshotResponse_Body, st *protostatus.Status, req *protonetmap.NetmapSnapshotRequest) (*protonetmap.NetmapSnapshotResponse, error) { resp := &protonetmap.NetmapSnapshotResponse{ Body: body, MetaHeader: s.makeResponseMetaHeader(st), } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeStatusNetmapResponse(err error) (*protonetmap.NetmapSnapshotResponse, error) { - return s.makeNetmapResponse(nil, util.ToStatus(err)) +func (s *server) makeStatusNetmapResponse(err error, req *protonetmap.NetmapSnapshotRequest) (*protonetmap.NetmapSnapshotResponse, error) { + return s.makeNetmapResponse(nil, util.ToStatus(err), req) } // NetmapSnapshot returns current network map from the underlying [Contract]. func (s *server) NetmapSnapshot(_ context.Context, req *protonetmap.NetmapSnapshotRequest) (*protonetmap.NetmapSnapshotResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeStatusNetmapResponse(err) + return s.makeStatusNetmapResponse(err, req) } n, err := s.contract.GetNetworkMap() if err != nil { - return s.makeStatusNetmapResponse(err) + return s.makeStatusNetmapResponse(err, req) } body := &protonetmap.NetmapSnapshotResponse_Body{ Netmap: n.ProtoMessage(), } - return s.makeNetmapResponse(body, util.StatusOK) + return s.makeNetmapResponse(body, util.StatusOK, req) } diff --git a/pkg/services/object/get/get_test.go b/pkg/services/object/get/get_test.go index 79d09b1431..b6f406b893 100644 --- a/pkg/services/object/get/get_test.go +++ b/pkg/services/object/get/get_test.go @@ -113,7 +113,7 @@ func newTestClient() *testClient { } } -func (c *testClient) getObject(exec *execCtx, _ client.NodeInfo) (*objectSDK.Object, error) { +func (c *testClient) getObject(exec *execCtx) (*objectSDK.Object, error) { v, ok := c.results[exec.address().EncodeToString()] if !ok { var errNotFound apistatus.ObjectNotFound diff --git a/pkg/services/object/get/prm.go b/pkg/services/object/get/prm.go index 50841d41e1..2855fcfea4 100644 --- a/pkg/services/object/get/prm.go +++ b/pkg/services/object/get/prm.go @@ -37,8 +37,8 @@ type RangeHashPrm struct { forwardedRangeHashResponse [][]byte } -type RequestForwarder func(context.Context, coreclient.NodeInfo, coreclient.MultiAddressClient) (*object.Object, error) -type RangeRequestForwarder func(context.Context, coreclient.NodeInfo, coreclient.MultiAddressClient) ([][]byte, error) +type RequestForwarder func(context.Context, coreclient.MultiAddressClient) (*object.Object, error) +type RangeRequestForwarder func(context.Context, coreclient.MultiAddressClient) ([][]byte, error) // HeadPrm groups parameters of Head service call. type HeadPrm struct { diff --git a/pkg/services/object/get/remote.go b/pkg/services/object/get/remote.go index 37c1e92892..eb585eb2ef 100644 --- a/pkg/services/object/get/remote.go +++ b/pkg/services/object/get/remote.go @@ -21,7 +21,7 @@ func (exec *execCtx) processNode(info client.NodeInfo) bool { return true } - obj, err := remoteClient.getObject(exec, info) + obj, err := remoteClient.getObject(exec) var errSplitInfo *objectSDK.SplitInfoError diff --git a/pkg/services/object/get/service.go b/pkg/services/object/get/service.go index 94d2456bb6..336e383737 100644 --- a/pkg/services/object/get/service.go +++ b/pkg/services/object/get/service.go @@ -41,7 +41,7 @@ type Service struct { type Option func(*cfg) type getClient interface { - getObject(*execCtx, client.NodeInfo) (*object.Object, error) + getObject(*execCtx) (*object.Object, error) } type cfg struct { diff --git a/pkg/services/object/get/util.go b/pkg/services/object/get/util.go index da5e22571d..18ff81df66 100644 --- a/pkg/services/object/get/util.go +++ b/pkg/services/object/get/util.go @@ -82,9 +82,9 @@ func (c *clientCacheWrapper) get(info coreclient.NodeInfo) (getClient, error) { }, nil } -func (c *clientWrapper) getObject(exec *execCtx, info coreclient.NodeInfo) (*object.Object, error) { +func (c *clientWrapper) getObject(exec *execCtx) (*object.Object, error) { if exec.isForwardingEnabled() { - return exec.prm.forwarder(exec.ctx, info, c.client) + return exec.prm.forwarder(exec.ctx, c.client) } key, err := exec.key() @@ -117,7 +117,7 @@ func (c *clientWrapper) getObject(exec *execCtx, info coreclient.NodeInfo) (*obj } if rngH := exec.prmRangeHash; rngH != nil && exec.isRangeHashForwardingEnabled() { - exec.prmRangeHash.forwardedRangeHashResponse, err = exec.prm.rangeForwarder(exec.ctx, info, c.client) + exec.prmRangeHash.forwardedRangeHashResponse, err = exec.prm.rangeForwarder(exec.ctx, c.client) return nil, err } diff --git a/pkg/services/object/internal/key.go b/pkg/services/object/internal/key.go deleted file mode 100644 index ce86b6cfb7..0000000000 --- a/pkg/services/object/internal/key.go +++ /dev/null @@ -1,19 +0,0 @@ -package internal - -import ( - "bytes" - - "github.com/nspcc-dev/neofs-node/pkg/core/client" - protosession "github.com/nspcc-dev/neofs-sdk-go/proto/session" -) - -// VerifyResponseKeyV2 checks if response is signed with expected key. Returns client.ErrWrongPublicKey if not. -func VerifyResponseKeyV2(expectedKey []byte, resp interface { - GetVerifyHeader() *protosession.ResponseVerificationHeader -}) error { - if !bytes.Equal(resp.GetVerifyHeader().GetBodySignature().GetKey(), expectedKey) { - return client.ErrWrongPublicKey - } - - return nil -} diff --git a/pkg/services/object/put/prm.go b/pkg/services/object/put/prm.go index 7232b004a9..01d746f08f 100644 --- a/pkg/services/object/put/prm.go +++ b/pkg/services/object/put/prm.go @@ -17,7 +17,7 @@ type PutInitPrm struct { copiesNumber uint32 - relay func(client.NodeInfo, client.MultiAddressClient) error + relay func(client.MultiAddressClient) error containerNodes ContainerNodes localNodeInContainer bool @@ -46,7 +46,7 @@ func (p *PutInitPrm) WithObject(v *object.Object) *PutInitPrm { return p } -func (p *PutInitPrm) WithRelay(f func(client.NodeInfo, client.MultiAddressClient) error) *PutInitPrm { +func (p *PutInitPrm) WithRelay(f func(client.MultiAddressClient) error) *PutInitPrm { if p != nil { p.relay = f } diff --git a/pkg/services/object/put/streamer.go b/pkg/services/object/put/streamer.go index 05d0d9fffd..3157ac700b 100644 --- a/pkg/services/object/put/streamer.go +++ b/pkg/services/object/put/streamer.go @@ -21,7 +21,7 @@ type Streamer struct { target internal.Target - relay func(client.NodeInfo, client.MultiAddressClient) error + relay func(client.MultiAddressClient) error maxPayloadSz uint64 // network config @@ -196,7 +196,7 @@ func (p *Streamer) newCommonTarget(prm *PutInitPrm) internal.Target { return fmt.Errorf("could not create SDK client %s: %w", node.info.AddressGroup(), err) } - return p.relay(node.info, c) + return p.relay(c) } } diff --git a/pkg/services/object/search/container.go b/pkg/services/object/search/container.go index abc2c13526..677a945e6a 100644 --- a/pkg/services/object/search/container.go +++ b/pkg/services/object/search/container.go @@ -74,7 +74,7 @@ func (exec *execCtx) executeOnContainer(ectx context.Context) { return } - ids, err := c.searchObjects(ctx, exec, info) + ids, err := c.searchObjects(ctx, exec) if err != nil { lg.Debug("remote operation failed", zap.Error(err)) diff --git a/pkg/services/object/search/prm.go b/pkg/services/object/search/prm.go index 0baf8c615c..158212efb7 100644 --- a/pkg/services/object/search/prm.go +++ b/pkg/services/object/search/prm.go @@ -29,7 +29,7 @@ type IDListWriter interface { // RequestForwarder is a callback for forwarding of the // original Search requests. -type RequestForwarder func(coreclient.NodeInfo, coreclient.MultiAddressClient) ([]oid.ID, error) +type RequestForwarder func(coreclient.MultiAddressClient) ([]oid.ID, error) // SetCommonParameters sets common parameters of the operation. func (p *Prm) SetCommonParameters(common *util.CommonPrm) { diff --git a/pkg/services/object/search/search_test.go b/pkg/services/object/search/search_test.go index 683c6d48d5..4af848c146 100644 --- a/pkg/services/object/search/search_test.go +++ b/pkg/services/object/search/search_test.go @@ -115,7 +115,7 @@ func (ts *testStorage) search(exec *execCtx) ([]oid.ID, error) { return v.ids, v.err } -func (ts *testStorage) searchObjects(_ context.Context, exec *execCtx, _ clientcore.NodeInfo) ([]oid.ID, error) { +func (ts *testStorage) searchObjects(_ context.Context, exec *execCtx) ([]oid.ID, error) { v, ok := ts.items[exec.containerID().EncodeToString()] if !ok { return nil, nil diff --git a/pkg/services/object/search/service.go b/pkg/services/object/search/service.go index 646bb70712..4a8dbcc5e4 100644 --- a/pkg/services/object/search/service.go +++ b/pkg/services/object/search/service.go @@ -25,7 +25,7 @@ type Option func(*cfg) type searchClient interface { // searchObjects searches objects on the specified node. // MUST NOT modify execCtx as it can be accessed concurrently. - searchObjects(context.Context, *execCtx, client.NodeInfo) ([]oid.ID, error) + searchObjects(context.Context, *execCtx) ([]oid.ID, error) } // Containers provides information about NeoFS containers necessary for the diff --git a/pkg/services/object/search/util.go b/pkg/services/object/search/util.go index 907be2631c..3d33b62940 100644 --- a/pkg/services/object/search/util.go +++ b/pkg/services/object/search/util.go @@ -69,9 +69,9 @@ func (c *clientConstructorWrapper) get(info client.NodeInfo) (searchClient, erro }, nil } -func (c *clientWrapper) searchObjects(ctx context.Context, exec *execCtx, info client.NodeInfo) ([]oid.ID, error) { +func (c *clientWrapper) searchObjects(ctx context.Context, exec *execCtx) ([]oid.ID, error) { if exec.prm.forwarder != nil { - return exec.prm.forwarder(info, c.client) + return exec.prm.forwarder(c.client) } var sessionInfo *util.SessionInfo diff --git a/pkg/services/object/server.go b/pkg/services/object/server.go index 7f784f3990..ec2c3a61f4 100644 --- a/pkg/services/object/server.go +++ b/pkg/services/object/server.go @@ -24,7 +24,6 @@ import ( aclsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/acl/v2" deletesvc "github.com/nspcc-dev/neofs-node/pkg/services/object/delete" getsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/get" - "github.com/nspcc-dev/neofs-node/pkg/services/object/internal" putsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/put" searchsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/search" objutil "github.com/nspcc-dev/neofs-node/pkg/services/object/util" @@ -233,15 +232,15 @@ func (s *Server) makeResponseMetaHeader(st *protostatus.Status) *protosession.Re } } -func (s *Server) sendPutResponse(stream protoobject.ObjectService_PutServer, resp *protoobject.PutResponse) error { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) sendPutResponse(stream protoobject.ObjectService_PutServer, resp *protoobject.PutResponse, req *protoobject.PutRequest) error { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return stream.SendAndClose(resp) } -func (s *Server) sendStatusPutResponse(stream protoobject.ObjectService_PutServer, err error) error { +func (s *Server) sendStatusPutResponse(stream protoobject.ObjectService_PutServer, err error, req *protoobject.PutRequest) error { return s.sendPutResponse(stream, &protoobject.PutResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } type putStream struct { @@ -264,15 +263,13 @@ func newIntermediatePutStream(signer ecdsa.PrivateKey, base *putsvc.Streamer, ct } } -func (x *putStream) sendToRemoteNode(node client.NodeInfo, c client.MultiAddressClient) error { - nodePub := node.PublicKey() +func (x *putStream) sendToRemoteNode(c client.MultiAddressClient) error { return c.ForEachGRPCConn(x.ctx, func(ctx context.Context, conn *grpc.ClientConn) error { - return putToRemoteNode(ctx, conn, nodePub, x.initReq, x.chunkReqs) // TODO: log error + return putToRemoteNode(ctx, conn, x.initReq, x.chunkReqs) // TODO: log error }) } -func putToRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, - initReq *protoobject.PutRequest, chunkReqs []*protoobject.PutRequest) error { +func putToRemoteNode(ctx context.Context, conn *grpc.ClientConn, initReq *protoobject.PutRequest, chunkReqs []*protoobject.PutRequest) error { stream, err := protoobject.NewObjectServiceClient(conn).Put(ctx) if err != nil { return fmt.Errorf("stream opening failed: %w", err) @@ -293,12 +290,6 @@ func putToRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, return fmt.Errorf("closing the stream failed: %w", err) } - if err := internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return fmt.Errorf("response verification failed: %w", err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return fmt.Errorf("remote node response: %w", err) } @@ -418,7 +409,7 @@ func (s *Server) Put(gStream protoobject.ObjectService_PutServer) error { return err } - var req *protoobject.PutRequest + var req, reqFirst *protoobject.PutRequest var resp *protoobject.PutResponse ps := newIntermediatePutStream(s.signer, stream, gStream.Context()) @@ -427,26 +418,30 @@ func (s *Server) Put(gStream protoobject.ObjectService_PutServer) error { if errors.Is(err, io.EOF) { resp, err = ps.close() if err != nil { - return s.sendStatusPutResponse(gStream, err) + return s.sendStatusPutResponse(gStream, err, reqFirst) } - err = s.sendPutResponse(gStream, resp) + err = s.sendPutResponse(gStream, resp, reqFirst) return err } return err } + if reqFirst == nil { + reqFirst = req + } + if c := req.GetBody().GetChunk(); c != nil { s.metrics.AddPutPayload(len(c)) } if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - err = s.sendStatusPutResponse(gStream, err) // assign for defer + err = s.sendStatusPutResponse(gStream, err, reqFirst) // assign for defer return err } if s.fsChain.LocalNodeUnderMaintenance() { - return s.sendStatusPutResponse(gStream, apistatus.ErrNodeUnderMaintenance) + return s.sendStatusPutResponse(gStream, apistatus.ErrNodeUnderMaintenance, reqFirst) } if req.Body == nil { @@ -455,36 +450,36 @@ func (s *Server) Put(gStream protoobject.ObjectService_PutServer) error { if reqInfo, objOwner, err := s.reqInfoProc.PutRequestToInfo(req); err != nil { if !errors.Is(err, aclsvc.ErrSkipRequest) { - return s.sendStatusPutResponse(gStream, err) + return s.sendStatusPutResponse(gStream, err, reqFirst) } } else { if !s.aclChecker.CheckBasicACL(reqInfo) || !s.aclChecker.StickyBitCheck(reqInfo, objOwner) { err = basicACLErr(reqInfo) // needed for defer - return s.sendStatusPutResponse(gStream, err) + return s.sendStatusPutResponse(gStream, err, reqFirst) } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.sendStatusPutResponse(gStream, err) + return s.sendStatusPutResponse(gStream, err, reqFirst) } } if err = ps.forwardRequest(req); err != nil { - err = s.sendStatusPutResponse(gStream, err) // assign for defer + err = s.sendStatusPutResponse(gStream, err, reqFirst) // assign for defer return err } } } -func (s *Server) signDeleteResponse(resp *protoobject.DeleteResponse) *protoobject.DeleteResponse { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) signDeleteResponse(resp *protoobject.DeleteResponse, req *protoobject.DeleteRequest) *protoobject.DeleteResponse { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return resp } -func (s *Server) makeStatusDeleteResponse(err error) *protoobject.DeleteResponse { +func (s *Server) makeStatusDeleteResponse(err error, req *protoobject.DeleteRequest) *protoobject.DeleteResponse { return s.signDeleteResponse(&protoobject.DeleteResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } type deleteResponseBody protoobject.DeleteResponse_Body @@ -501,40 +496,40 @@ func (s *Server) Delete(ctx context.Context, req *protoobject.DeleteRequest) (*p defer func() { s.pushOpExecResult(stat.MethodObjectDelete, err, t) }() if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } if s.fsChain.LocalNodeUnderMaintenance() { - return s.makeStatusDeleteResponse(apistatus.ErrNodeUnderMaintenance), nil + return s.makeStatusDeleteResponse(apistatus.ErrNodeUnderMaintenance, req), nil } reqInfo, err := s.reqInfoProc.DeleteRequestToInfo(req) if err != nil { - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } ma := req.GetBody().GetAddress() if ma == nil { - return s.makeStatusDeleteResponse(errors.New("missing object address")), nil + return s.makeStatusDeleteResponse(errors.New("missing object address"), req), nil } var addr oid.Address err = addr.FromProtoMessage(ma) if err != nil { - return s.makeStatusDeleteResponse(fmt.Errorf("invalid object address: %w", err)), nil + return s.makeStatusDeleteResponse(fmt.Errorf("invalid object address: %w", err), req), nil } cp, err := objutil.CommonPrmFromRequest(req) if err != nil { - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } var rb protoobject.DeleteResponse_Body @@ -545,18 +540,18 @@ func (s *Server) Delete(ctx context.Context, req *protoobject.DeleteRequest) (*p p.WithTombstoneAddressTarget((*deleteResponseBody)(&rb)) err = s.handlers.Delete(ctx, p) if err != nil { - return s.makeStatusDeleteResponse(err), nil + return s.makeStatusDeleteResponse(err, req), nil } - return s.signDeleteResponse(&protoobject.DeleteResponse{Body: &rb}), nil + return s.signDeleteResponse(&protoobject.DeleteResponse{Body: &rb}, req), nil } -func (s *Server) signHeadResponse(resp *protoobject.HeadResponse) *protoobject.HeadResponse { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) signHeadResponse(resp *protoobject.HeadResponse, req *protoobject.HeadRequest) *protoobject.HeadResponse { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return resp } -func (s *Server) makeStatusHeadResponse(err error) *protoobject.HeadResponse { +func (s *Server) makeStatusHeadResponse(err error, req *protoobject.HeadRequest) *protoobject.HeadResponse { var splitErr *object.SplitInfoError if errors.As(err, &splitErr) { return s.signHeadResponse(&protoobject.HeadResponse{ @@ -565,11 +560,11 @@ func (s *Server) makeStatusHeadResponse(err error) *protoobject.HeadResponse { SplitInfo: splitErr.SplitInfo().ProtoMessage(), }, }, - }) + }, req) } return s.signHeadResponse(&protoobject.HeadResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } func (s *Server) Head(ctx context.Context, req *protoobject.HeadRequest) (*protoobject.HeadResponse, error) { @@ -580,44 +575,44 @@ func (s *Server) Head(ctx context.Context, req *protoobject.HeadRequest) (*proto defer func() { s.pushOpExecResult(stat.MethodObjectHead, err, t) }() if err := icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } if s.fsChain.LocalNodeUnderMaintenance() { - return s.makeStatusHeadResponse(apistatus.ErrNodeUnderMaintenance), nil + return s.makeStatusHeadResponse(apistatus.ErrNodeUnderMaintenance, req), nil } reqInfo, err := s.reqInfoProc.HeadRequestToInfo(req) if err != nil { - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } var resp protoobject.HeadResponse p, err := convertHeadPrm(s.signer, req, &resp) if err != nil { - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } err = s.handlers.Head(ctx, p) if err != nil { - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } err = s.aclChecker.CheckEACL(&resp, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // defer - return s.makeStatusHeadResponse(err), nil + return s.makeStatusHeadResponse(err, req), nil } - return s.signHeadResponse(&resp), nil + return s.signHeadResponse(&resp, req), nil } type headResponse struct { @@ -691,7 +686,7 @@ func convertHeadPrm(signer ecdsa.PrivateKey, req *protoobject.HeadRequest, resp if meta == nil { return getsvc.HeadPrm{}, errors.New("missing meta header") } - p.SetRequestForwarder(func(ctx context.Context, node client.NodeInfo, c client.MultiAddressClient) (*object.Object, error) { + p.SetRequestForwarder(func(ctx context.Context, c client.MultiAddressClient) (*object.Object, error) { var err error onceResign.Do(func() { req.MetaHeader = &protosession.RequestMetaHeader{ @@ -705,29 +700,22 @@ func convertHeadPrm(signer ecdsa.PrivateKey, req *protoobject.HeadRequest, resp return nil, err } - nodePub := node.PublicKey() var hdr *object.Object return hdr, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { var err error - hdr, err = getHeaderFromRemoteNode(ctx, conn, nodePub, req) + hdr, err = getHeaderFromRemoteNode(ctx, conn, req) return err // TODO: log error }) }) return p, nil } -func getHeaderFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, req *protoobject.HeadRequest) (*object.Object, error) { +func getHeaderFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, req *protoobject.HeadRequest) (*object.Object, error) { resp, err := protoobject.NewObjectServiceClient(conn).Head(ctx, req) if err != nil { return nil, fmt.Errorf("sending the request failed: %w", err) } - if err := internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return nil, err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return nil, fmt.Errorf("response verification failed: %w", err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return nil, err } @@ -798,15 +786,15 @@ func getHeaderFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub return obj, nil } -func (s *Server) signHashResponse(resp *protoobject.GetRangeHashResponse) *protoobject.GetRangeHashResponse { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) signHashResponse(resp *protoobject.GetRangeHashResponse, req *protoobject.GetRangeHashRequest) *protoobject.GetRangeHashResponse { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return resp } -func (s *Server) makeStatusHashResponse(err error) *protoobject.GetRangeHashResponse { +func (s *Server) makeStatusHashResponse(err error, req *protoobject.GetRangeHashRequest) *protoobject.GetRangeHashResponse { return s.signHashResponse(&protoobject.GetRangeHashResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } // GetRangeHash converts gRPC GetRangeHashRequest message and passes it to internal Object service. @@ -817,41 +805,41 @@ func (s *Server) GetRangeHash(ctx context.Context, req *protoobject.GetRangeHash ) defer func() { s.pushOpExecResult(stat.MethodObjectHash, err, t) }() if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } if s.fsChain.LocalNodeUnderMaintenance() { - return s.makeStatusHashResponse(apistatus.ErrNodeUnderMaintenance), nil + return s.makeStatusHashResponse(apistatus.ErrNodeUnderMaintenance, req), nil } reqInfo, err := s.reqInfoProc.HashRequestToInfo(req) if err != nil { - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } p, err := convertHashPrm(s.signer, s.storage, req) if err != nil { - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } res, err := s.handlers.GetRangeHash(ctx, p) if err != nil { - return s.makeStatusHashResponse(err), nil + return s.makeStatusHashResponse(err, req), nil } return s.signHashResponse(&protoobject.GetRangeHashResponse{ Body: &protoobject.GetRangeHashResponse_Body{ Type: req.Body.Type, HashList: res.Hashes(), - }}), nil + }}, req), nil } // converts original request into parameters accepted by the internal handler. @@ -916,7 +904,7 @@ func convertHashPrm(signer ecdsa.PrivateKey, ss sessions, req *protoobject.GetRa if meta == nil { return getsvc.RangeHashPrm{}, errors.New("missing meta header") } - p.SetRangeHashRequestForwarder(func(ctx context.Context, node client.NodeInfo, c client.MultiAddressClient) ([][]byte, error) { + p.SetRangeHashRequestForwarder(func(ctx context.Context, c client.MultiAddressClient) ([][]byte, error) { var err error onceResign.Do(func() { req.MetaHeader = &protosession.RequestMetaHeader{ @@ -931,30 +919,22 @@ func convertHashPrm(signer ecdsa.PrivateKey, ss sessions, req *protoobject.GetRa return nil, err } - nodePub := node.PublicKey() var hs [][]byte return hs, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { var err error - hs, err = getHashesFromRemoteNode(ctx, conn, nodePub, req) + hs, err = getHashesFromRemoteNode(ctx, conn, req) return err // TODO: log error }) }) return p, nil } -func getHashesFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, - req *protoobject.GetRangeHashRequest) ([][]byte, error) { +func getHashesFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, req *protoobject.GetRangeHashRequest) ([][]byte, error) { resp, err := protoobject.NewObjectServiceClient(conn).GetRangeHash(ctx, req) if err != nil { return nil, fmt.Errorf("GetRangeHash rpc failure: %w", err) } - if err := internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return nil, err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return nil, fmt.Errorf("response verification failed: %w", err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return nil, err } @@ -962,12 +942,12 @@ func getHashesFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub return resp.GetBody().GetHashList(), nil } -func (s *Server) sendGetResponse(stream protoobject.ObjectService_GetServer, resp *protoobject.GetResponse) error { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) sendGetResponse(stream protoobject.ObjectService_GetServer, resp *protoobject.GetResponse, req *protoobject.GetRequest) error { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return stream.Send(resp) } -func (s *Server) sendStatusGetResponse(stream protoobject.ObjectService_GetServer, err error) error { +func (s *Server) sendStatusGetResponse(stream protoobject.ObjectService_GetServer, err error, req *protoobject.GetRequest) error { var splitErr *object.SplitInfoError if errors.As(err, &splitErr) { return s.sendGetResponse(stream, &protoobject.GetResponse{ @@ -976,17 +956,18 @@ func (s *Server) sendStatusGetResponse(stream protoobject.ObjectService_GetServe SplitInfo: splitErr.SplitInfo().ProtoMessage(), }, }, - }) + }, req) } return s.sendGetResponse(stream, &protoobject.GetResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } type getStream struct { base protoobject.ObjectService_GetServer srv *Server reqInfo aclsvc.RequestInfo + req *protoobject.GetRequest } func (s *getStream) WriteHeader(hdr *object.Object) error { @@ -1003,7 +984,7 @@ func (s *getStream) WriteHeader(hdr *object.Object) error { if err := s.srv.aclChecker.CheckEACL(resp, s.reqInfo); err != nil { return eACLErr(s.reqInfo, err) } - return s.srv.sendGetResponse(s.base, resp) + return s.srv.sendGetResponse(s.base, resp, s.req) } func (s *getStream) WriteChunk(chunk []byte) error { @@ -1015,7 +996,7 @@ func (s *getStream) WriteChunk(chunk []byte) error { }, }, } - if err := s.srv.sendGetResponse(s.base, newResp); err != nil { + if err := s.srv.sendGetResponse(s.base, newResp, s.req); err != nil { return err } } @@ -1030,38 +1011,39 @@ func (s *Server) Get(req *protoobject.GetRequest, gStream protoobject.ObjectServ ) defer func() { s.pushOpExecResult(stat.MethodObjectGet, err, t) }() if err = icrypto.VerifyRequestSignatures(req); err != nil { - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } if s.fsChain.LocalNodeUnderMaintenance() { - return s.sendStatusGetResponse(gStream, apistatus.ErrNodeUnderMaintenance) + return s.sendStatusGetResponse(gStream, apistatus.ErrNodeUnderMaintenance, req) } reqInfo, err := s.reqInfoProc.GetRequestToInfo(req) if err != nil { - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } p, err := convertGetPrm(s.signer, req, &getStream{ base: gStream, srv: s, reqInfo: reqInfo, + req: req, }) if err != nil { - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } err = s.handlers.Get(gStream.Context(), p) if err != nil { - return s.sendStatusGetResponse(gStream, err) + return s.sendStatusGetResponse(gStream, err, req) } return nil } @@ -1102,7 +1084,7 @@ func convertGetPrm(signer ecdsa.PrivateKey, req *protoobject.GetRequest, stream if meta == nil { return getsvc.Prm{}, errors.New("missing meta header") } - p.SetRequestForwarder(func(ctx context.Context, node client.NodeInfo, c client.MultiAddressClient) (*object.Object, error) { + p.SetRequestForwarder(func(ctx context.Context, c client.MultiAddressClient) (*object.Object, error) { var err error onceResign.Do(func() { req.MetaHeader = &protosession.RequestMetaHeader{ @@ -1116,9 +1098,8 @@ func convertGetPrm(signer ecdsa.PrivateKey, req *protoobject.GetRequest, stream return nil, err } - nodePub := node.PublicKey() return nil, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { - err := continueGetFromRemoteNode(ctx, conn, nodePub, req, stream, &onceHdr, &respondedPayload) + err := continueGetFromRemoteNode(ctx, conn, req, stream, &onceHdr, &respondedPayload) if errors.Is(err, io.EOF) { return nil } @@ -1128,8 +1109,7 @@ func convertGetPrm(signer ecdsa.PrivateKey, req *protoobject.GetRequest, stream return p, nil } -func continueGetFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, req *protoobject.GetRequest, - stream *getStream, onceHdr *sync.Once, respondedPayload *int) error { +func continueGetFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, req *protoobject.GetRequest, stream *getStream, onceHdr *sync.Once, respondedPayload *int) error { getStream, err := protoobject.NewObjectServiceClient(conn).Get(ctx, req) if err != nil { return fmt.Errorf("stream opening failed: %w", err) @@ -1149,12 +1129,6 @@ func continueGetFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodeP return fmt.Errorf("reading the response failed: %w", err) } - if err = internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return fmt.Errorf("response verification failed: %w", err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return err } @@ -1215,12 +1189,12 @@ func continueGetFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodeP } } -func (s *Server) sendRangeResponse(stream protoobject.ObjectService_GetRangeServer, resp *protoobject.GetRangeResponse) error { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) sendRangeResponse(stream protoobject.ObjectService_GetRangeServer, resp *protoobject.GetRangeResponse, req *protoobject.GetRangeRequest) error { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return stream.Send(resp) } -func (s *Server) sendStatusRangeResponse(stream protoobject.ObjectService_GetRangeServer, err error) error { +func (s *Server) sendStatusRangeResponse(stream protoobject.ObjectService_GetRangeServer, err error, req *protoobject.GetRangeRequest) error { var splitErr *object.SplitInfoError if errors.As(err, &splitErr) { return s.sendRangeResponse(stream, &protoobject.GetRangeResponse{ @@ -1229,17 +1203,18 @@ func (s *Server) sendStatusRangeResponse(stream protoobject.ObjectService_GetRan SplitInfo: splitErr.SplitInfo().ProtoMessage(), }, }, - }) + }, req) } return s.sendRangeResponse(stream, &protoobject.GetRangeResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } type rangeStream struct { base protoobject.ObjectService_GetRangeServer srv *Server reqInfo aclsvc.RequestInfo + req *protoobject.GetRangeRequest } func (s *rangeStream) WriteChunk(chunk []byte) error { @@ -1256,7 +1231,7 @@ func (s *rangeStream) WriteChunk(chunk []byte) error { if err := s.srv.aclChecker.CheckEACL(newResp, s.reqInfo); err != nil { return eACLErr(s.reqInfo, err) } - if err := s.srv.sendRangeResponse(s.base, newResp); err != nil { + if err := s.srv.sendRangeResponse(s.base, newResp, s.req); err != nil { return err } } @@ -1270,38 +1245,39 @@ func (s *Server) GetRange(req *protoobject.GetRangeRequest, gStream protoobject. ) defer func() { s.pushOpExecResult(stat.MethodObjectRange, err, t) }() if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } if s.fsChain.LocalNodeUnderMaintenance() { - return s.sendStatusRangeResponse(gStream, apistatus.ErrNodeUnderMaintenance) + return s.sendStatusRangeResponse(gStream, apistatus.ErrNodeUnderMaintenance, req) } reqInfo, err := s.reqInfoProc.RangeRequestToInfo(req) if err != nil { - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) // needed for defer - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } p, err := convertRangePrm(s.signer, req, &rangeStream{ base: gStream, srv: s, reqInfo: reqInfo, + req: req, }) if err != nil { - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } err = s.handlers.GetRange(gStream.Context(), p) if err != nil { - return s.sendStatusRangeResponse(gStream, err) + return s.sendStatusRangeResponse(gStream, err, req) } return nil } @@ -1354,7 +1330,7 @@ func convertRangePrm(signer ecdsa.PrivateKey, req *protoobject.GetRangeRequest, if meta == nil { return getsvc.RangePrm{}, errors.New("missing meta header") } - p.SetRequestForwarder(func(ctx context.Context, node client.NodeInfo, c client.MultiAddressClient) (*object.Object, error) { + p.SetRequestForwarder(func(ctx context.Context, c client.MultiAddressClient) (*object.Object, error) { var err error onceResign.Do(func() { req.MetaHeader = &protosession.RequestMetaHeader{ @@ -1368,9 +1344,8 @@ func convertRangePrm(signer ecdsa.PrivateKey, req *protoobject.GetRangeRequest, return nil, err } - nodePub := node.PublicKey() return nil, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { - err := continueRangeFromRemoteNode(ctx, conn, nodePub, req, stream, &respondedPayload) + err := continueRangeFromRemoteNode(ctx, conn, req, stream, &respondedPayload) if errors.Is(err, io.EOF) { return nil } @@ -1380,8 +1355,7 @@ func convertRangePrm(signer ecdsa.PrivateKey, req *protoobject.GetRangeRequest, return p, nil } -func continueRangeFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, req *protoobject.GetRangeRequest, - stream *rangeStream, respondedPayload *int) error { +func continueRangeFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, req *protoobject.GetRangeRequest, stream *rangeStream, respondedPayload *int) error { rangeStream, err := protoobject.NewObjectServiceClient(conn).GetRange(ctx, req) if err != nil { return fmt.Errorf("stream opening failed: %w", err) @@ -1397,12 +1371,6 @@ func continueRangeFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nod return fmt.Errorf("reading the response failed: %w", err) } - if err = internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return fmt.Errorf("response verification failed: %w", err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return err } @@ -1436,21 +1404,22 @@ func continueRangeFromRemoteNode(ctx context.Context, conn *grpc.ClientConn, nod } } -func (s *Server) sendSearchResponse(stream protoobject.ObjectService_SearchServer, resp *protoobject.SearchResponse) error { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) sendSearchResponse(stream protoobject.ObjectService_SearchServer, resp *protoobject.SearchResponse, req *protoobject.SearchRequest) error { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return stream.Send(resp) } -func (s *Server) sendStatusSearchResponse(stream protoobject.ObjectService_SearchServer, err error) error { +func (s *Server) sendStatusSearchResponse(stream protoobject.ObjectService_SearchServer, err error, req *protoobject.SearchRequest) error { return s.sendSearchResponse(stream, &protoobject.SearchResponse{ MetaHeader: s.makeResponseMetaHeader(util.ToStatus(err)), - }) + }, req) } type searchStream struct { base protoobject.ObjectService_SearchServer srv *Server reqInfo aclsvc.RequestInfo + req *protoobject.SearchRequest } func (s *searchStream) WriteIDs(ids []oid.ID) error { @@ -1474,7 +1443,7 @@ func (s *searchStream) WriteIDs(ids []oid.ID) error { if err := s.srv.aclChecker.CheckEACL(r, s.reqInfo); err != nil { return eACLErr(s.reqInfo, err) } - if err := s.srv.sendSearchResponse(s.base, r); err != nil { + if err := s.srv.sendSearchResponse(s.base, r, s.req); err != nil { return err } @@ -1490,38 +1459,39 @@ func (s *Server) Search(req *protoobject.SearchRequest, gStream protoobject.Obje ) defer func() { s.pushOpExecResult(stat.MethodObjectSearch, err, t) }() if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } if s.fsChain.LocalNodeUnderMaintenance() { - return s.sendStatusSearchResponse(gStream, apistatus.ErrNodeUnderMaintenance) + return s.sendStatusSearchResponse(gStream, apistatus.ErrNodeUnderMaintenance, req) } reqInfo, err := s.reqInfoProc.SearchRequestToInfo(req) if err != nil { - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } p, err := convertSearchPrm(gStream.Context(), s.signer, req, &searchStream{ base: gStream, srv: s, reqInfo: reqInfo, + req: req, }) if err != nil { - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } err = s.handlers.Search(gStream.Context(), p) if err != nil { - return s.sendStatusSearchResponse(gStream, err) + return s.sendStatusSearchResponse(gStream, err, req) } return nil } @@ -1567,7 +1537,7 @@ func convertSearchPrm(ctx context.Context, signer ecdsa.PrivateKey, req *protoob if meta == nil { return searchsvc.Prm{}, errors.New("missing meta header") } - p.SetRequestForwarder(func(node client.NodeInfo, c client.MultiAddressClient) ([]oid.ID, error) { + p.SetRequestForwarder(func(c client.MultiAddressClient) ([]oid.ID, error) { var err error onceResign.Do(func() { req.MetaHeader = &protosession.RequestMetaHeader{ @@ -1581,18 +1551,17 @@ func convertSearchPrm(ctx context.Context, signer ecdsa.PrivateKey, req *protoob return nil, err } - nodePub := node.PublicKey() var res []oid.ID return res, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { var err error - res, err = searchOnRemoteNode(ctx, conn, nodePub, req) + res, err = searchOnRemoteNode(ctx, conn, req) return err // TODO: log error }) }) return p, nil } -func searchOnRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, req *protoobject.SearchRequest) ([]oid.ID, error) { +func searchOnRemoteNode(ctx context.Context, conn *grpc.ClientConn, req *protoobject.SearchRequest) ([]oid.ID, error) { searchStream, err := protoobject.NewObjectServiceClient(conn).Search(ctx, req) if err != nil { return nil, err @@ -1608,12 +1577,6 @@ func searchOnRemoteNode(ctx context.Context, conn *grpc.ClientConn, nodePub []by return nil, fmt.Errorf("reading the response failed: %w", err) } - if err := internal.VerifyResponseKeyV2(nodePub, resp); err != nil { - return nil, err - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return nil, fmt.Errorf("could not verify %T: %w", resp, err) - } if err := checkStatus(resp.GetMetaHeader().GetStatus()); err != nil { return nil, fmt.Errorf("remote node response: %w", err) } @@ -1799,15 +1762,15 @@ func (s *Server) Replicate(_ context.Context, req *protoobject.ReplicateRequest) return resp, nil } -func (s *Server) signSearchResponse(resp *protoobject.SearchV2Response) *protoobject.SearchV2Response { - resp.VerifyHeader = util.SignResponse(&s.signer, resp) +func (s *Server) signSearchResponse(resp *protoobject.SearchV2Response, req *protoobject.SearchV2Request) *protoobject.SearchV2Response { + resp.VerifyHeader = util.SignResponse(&s.signer, resp, req) return resp } -func (s *Server) makeStatusSearchResponse(err error) *protoobject.SearchV2Response { +func (s *Server) makeStatusSearchResponse(err error, req *protoobject.SearchV2Request) *protoobject.SearchV2Response { return s.signSearchResponse(&protoobject.SearchV2Response{ MetaHeader: s.makeResponseMetaHeader(apistatus.FromError(err)), - }) + }, req) } func (s *Server) SearchV2(ctx context.Context, req *protoobject.SearchV2Request) (*protoobject.SearchV2Response, error) { @@ -1817,32 +1780,32 @@ func (s *Server) SearchV2(ctx context.Context, req *protoobject.SearchV2Request) ) defer s.pushOpExecResult(stat.MethodObjectSearchV2, err, t) if err = icrypto.VerifyRequestSignaturesN3(req, s.fsChain); err != nil { - return s.makeStatusSearchResponse(err), nil + return s.makeStatusSearchResponse(err, req), nil } if s.fsChain.LocalNodeUnderMaintenance() { - return s.makeStatusSearchResponse(apistatus.ErrNodeUnderMaintenance), nil + return s.makeStatusSearchResponse(apistatus.ErrNodeUnderMaintenance, req), nil } reqInfo, err := s.reqInfoProc.SearchV2RequestToInfo(req) if err != nil { - return s.makeStatusSearchResponse(err), nil + return s.makeStatusSearchResponse(err, req), nil } if !s.aclChecker.CheckBasicACL(reqInfo) { err = basicACLErr(reqInfo) // needed for defer - return s.makeStatusSearchResponse(err), nil + return s.makeStatusSearchResponse(err, req), nil } err = s.aclChecker.CheckEACL(req, reqInfo) if err != nil { err = eACLErr(reqInfo, err) - return s.makeStatusSearchResponse(err), nil + return s.makeStatusSearchResponse(err, req), nil } body, err := s.processSearchRequest(ctx, req) if err != nil { - return s.makeStatusSearchResponse(err), nil + return s.makeStatusSearchResponse(err, req), nil } - return s.signSearchResponse(&protoobject.SearchV2Response{Body: body}), nil + return s.signSearchResponse(&protoobject.SearchV2Response{Body: body}, req), nil } func verifySearchFilter(f *protoobject.SearchFilter) error { @@ -2094,24 +2057,17 @@ func (s *Server) searchOnRemoteNode(ctx context.Context, node sdknetmap.NodeInfo var more bool return items, more, c.ForEachGRPCConn(ctx, func(ctx context.Context, conn *grpc.ClientConn) error { var err error - items, more, err = searchOnRemoteAddress(ctx, conn, nodePub, req) + items, more, err = searchOnRemoteAddress(ctx, conn, req) return err // TODO: log error }) } -func searchOnRemoteAddress(ctx context.Context, conn *grpc.ClientConn, nodePub []byte, - req *protoobject.SearchV2Request) ([]sdkclient.SearchResultItem, bool, error) { +func searchOnRemoteAddress(ctx context.Context, conn *grpc.ClientConn, req *protoobject.SearchV2Request) ([]sdkclient.SearchResultItem, bool, error) { resp, err := protoobject.NewObjectServiceClient(conn).SearchV2(ctx, req) if err != nil { return nil, false, fmt.Errorf("send request over gRPC: %w", err) } - if !bytes.Equal(resp.GetVerifyHeader().GetBodySignature().GetKey(), nodePub) { - return nil, false, client.ErrWrongPublicKey - } - if err := neofscrypto.VerifyResponseWithBuffer(resp, nil); err != nil { - return nil, false, fmt.Errorf("response verification failed: %w", err) - } if err := apistatus.ToError(resp.GetMetaHeader().GetStatus()); err != nil { return nil, false, err } diff --git a/pkg/services/session/server.go b/pkg/services/session/server.go index 8e40ca330d..3153a821d1 100644 --- a/pkg/services/session/server.go +++ b/pkg/services/session/server.go @@ -46,7 +46,7 @@ func New(s *ecdsa.PrivateKey, net netmap.State, ks KeyStorage) protosession.Sess } } -func (s *server) makeCreateResponse(body *protosession.CreateResponse_Body, st *protostatus.Status) (*protosession.CreateResponse, error) { +func (s *server) makeCreateResponse(body *protosession.CreateResponse_Body, st *protostatus.Status, req *protosession.CreateRequest) (*protosession.CreateResponse, error) { resp := &protosession.CreateResponse{ Body: body, MetaHeader: &protosession.ResponseMetaHeader{ @@ -55,44 +55,44 @@ func (s *server) makeCreateResponse(body *protosession.CreateResponse_Body, st * Status: st, }, } - resp.VerifyHeader = util.SignResponse(s.signer, resp) + resp.VerifyHeader = util.SignResponse(s.signer, resp, req) return resp, nil } -func (s *server) makeFailedCreateResponse(err error) (*protosession.CreateResponse, error) { - return s.makeCreateResponse(nil, util.ToStatus(err)) +func (s *server) makeFailedCreateResponse(err error, req *protosession.CreateRequest) (*protosession.CreateResponse, error) { + return s.makeCreateResponse(nil, util.ToStatus(err), req) } // Create generates new private session key and saves it in the underlying // [KeyStorage]. func (s *server) Create(_ context.Context, req *protosession.CreateRequest) (*protosession.CreateResponse, error) { if err := icrypto.VerifyRequestSignatures(req); err != nil { - return s.makeFailedCreateResponse(err) + return s.makeFailedCreateResponse(err, req) } reqBody := req.GetBody() mUsr := reqBody.GetOwnerId() if mUsr == nil { - return s.makeFailedCreateResponse(errors.New("missing account")) + return s.makeFailedCreateResponse(errors.New("missing account"), req) } var usr user.ID if err := usr.FromProtoMessage(mUsr); err != nil { - return s.makeFailedCreateResponse(fmt.Errorf("invalid account: %w", err)) + return s.makeFailedCreateResponse(fmt.Errorf("invalid account: %w", err), req) } key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { - return s.makeFailedCreateResponse(fmt.Errorf("generate private key: %w", err)) + return s.makeFailedCreateResponse(fmt.Errorf("generate private key: %w", err), req) } uid := uuid.New() if err := s.keys.Store(*key, usr, uid[:], reqBody.Expiration); err != nil { - return s.makeFailedCreateResponse(fmt.Errorf("store private key locally: %w", err)) + return s.makeFailedCreateResponse(fmt.Errorf("store private key locally: %w", err), req) } body := &protosession.CreateResponse_Body{ Id: uid[:], SessionKey: neofscrypto.PublicKeyBytes((*neofsecdsa.PublicKey)(&key.PublicKey)), } - return s.makeCreateResponse(body, util.StatusOK) + return s.makeCreateResponse(body, util.StatusOK, req) } diff --git a/pkg/services/util/sign.go b/pkg/services/util/sign.go index 501a043f7a..5694362309 100644 --- a/pkg/services/util/sign.go +++ b/pkg/services/util/sign.go @@ -7,11 +7,24 @@ import ( apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" sdkcrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" sdkecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa" + "github.com/nspcc-dev/neofs-sdk-go/proto/refs" protosession "github.com/nspcc-dev/neofs-sdk-go/proto/session" protostatus "github.com/nspcc-dev/neofs-sdk-go/proto/status" ) -func SignResponse[R sdkcrypto.ProtoMessage](signer *ecdsa.PrivateKey, r sdkcrypto.SignedResponse[R]) *protosession.ResponseVerificationHeader { +func SignResponse[R sdkcrypto.ProtoMessage](signer *ecdsa.PrivateKey, r sdkcrypto.SignedResponse[R], req interface { + GetMetaHeader() *protosession.RequestMetaHeader +}) *protosession.ResponseVerificationHeader { + var ver *refs.Version + for mh := req.GetMetaHeader(); mh != nil; mh = mh.Origin { + if mh.Origin == nil { + ver = mh.Version + break + } + } + if ver.GetMajor() > 2 || (ver.GetMajor() == 2 && ver.GetMinor() > 17) { // getters are NPE-protected + return nil + } verHeader, err := sdkcrypto.SignResponseWithBuffer(sdkecdsa.Signer(*signer), r, nil) if err != nil { // We can't pass this error as NeoFS status code since response will be unsigned.