package util import ( "crypto/ecdsa" "errors" "fmt" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" ) type RequestMessage interface { GetMetaHeader() *session.RequestMetaHeader } // ResponseMessage is an interface of FrostFS response message. type ResponseMessage interface { GetMetaHeader() *session.ResponseMetaHeader SetMetaHeader(*session.ResponseMetaHeader) } type SignService struct { key *ecdsa.PrivateKey } var ErrAbortStream = errors.New("abort message stream") func NewUnarySignService(key *ecdsa.PrivateKey) *SignService { return &SignService{ key: key, } } // SignResponse response with private key via signature.SignServiceMessage. // The signature error affects the result depending on the protocol version: // - if status return is supported, panics since we cannot return the failed status, because it will not be signed. // - otherwise, returns error in order to transport it directly. func (s *SignService) SignResponse(resp ResponseMessage, err error) error { if err != nil { setStatusV2(resp, err) } err = signature.SignServiceMessage(s.key, resp) if err != nil { return fmt.Errorf("could not sign response: %w", err) } return nil } func (s *SignService) VerifyRequest(req RequestMessage) error { if err := signature.VerifyServiceMessage(req); err != nil { var sigErr apistatus.SignatureVerification sigErr.SetMessage(err.Error()) return sigErr } return nil } // EnsureNonNilResponse creates an appropriate response struct if it is nil. func EnsureNonNilResponse[T any](resp *T, err error) (*T, error) { if resp != nil { return resp, err } return new(T), err } func setStatusV2(resp ResponseMessage, err error) { // unwrap error for e := errors.Unwrap(err); e != nil; e = errors.Unwrap(err) { err = e } session.SetStatus(resp, apistatus.ToStatusV2(apistatus.ErrToStatus(err))) }