Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 61 additions & 16 deletions client/object_get.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package client

import (
"bytes"
"context"
"crypto/sha256"
"errors"
"fmt"
"hash"
"io"
"time"

"github.com/nspcc-dev/neofs-sdk-go/bearer"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsproto "github.com/nspcc-dev/neofs-sdk-go/internal/proto"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
protoobject "github.com/nspcc-dev/neofs-sdk-go/proto/object"
Expand Down Expand Up @@ -54,6 +58,13 @@
// PrmObjectGet groups optional parameters of ObjectGetInit operation.
type PrmObjectGet struct {
prmObjectRead
skipChecksumVerification bool
}

// SkipChecksumVerification allows to skip verification of received header
// against object ID and payload against its in-header checksum.
func (x *PrmObjectGet) SkipChecksumVerification() {
x.skipChecksumVerification = true
}

// used part of [protoobject.ObjectService_GetClient] simplifying test
Expand Down Expand Up @@ -84,6 +95,13 @@

statisticCallback shortStatisticCallback
startTime time.Time // if statisticCallback is set only

requestedOID oid.ID

verifyChecksums bool

payloadHashCheck []byte
payloadHashGot hash.Hash
}

// readHeader reads header of the object. Result means success.
Expand All @@ -99,11 +117,6 @@
return false
}

if x.err = neofscrypto.VerifyResponseWithBuffer[*protoobject.GetResponse_Body](resp, nil); x.err != nil {
x.err = fmt.Errorf("%w: %w", errResponseSignatures, x.err)
return false
}

if x.err = apistatus.ToError(resp.GetMetaHeader().GetStatus()); x.err != nil {
return false
}
Expand Down Expand Up @@ -154,7 +167,26 @@
Signature: partInit.Signature,
Header: partInit.Header,
})
return x.err == nil
if x.err != nil {
return false
}

if x.verifyChecksums {
hb := neofsproto.MarshalMessage(partInit.Header)
if oid.NewFromObjectHeaderBinary(hb) != x.requestedOID {
x.err = errors.New("received header mismatches ID")
return false
}

if partInit.Header.PayloadHash == nil {
x.err = errors.New("missing payload hash in header")
return false
}

Check warning on line 184 in client/object_get.go

View check run for this annotation

Codecov / codecov/patch

client/object_get.go#L182-L184

Added lines #L182 - L184 were not covered by tests
x.payloadHashGot = sha256.New()
x.payloadHashCheck = partInit.Header.PayloadHash.Sum
}

return true
}

func (x *PayloadReader) readChunk(buf []byte) (int, bool) {
Expand Down Expand Up @@ -183,11 +215,6 @@
return read, false
}

if x.err = neofscrypto.VerifyResponseWithBuffer[*protoobject.GetResponse_Body](resp, nil); x.err != nil {
x.err = fmt.Errorf("%w: %w", errResponseSignatures, x.err)
return read, false
}

if x.err = apistatus.ToError(resp.GetMetaHeader().GetStatus()); x.err != nil {
return read, false
}
Expand All @@ -210,6 +237,9 @@
continue
}

if x.verifyChecksums {
x.payloadHashGot.Write(chunk) // never returns an error according to docs
}
lastRead = copy(buf[read:], chunk)

read += lastRead
Expand All @@ -233,6 +263,9 @@
if x.remainingPayloadLen > 0 {
return io.ErrUnexpectedEOF
}
if x.verifyChecksums && !bytes.Equal(x.payloadHashGot.Sum(nil), x.payloadHashCheck) {
return errors.New("received payload mismatches checksum from header")
}
}
return x.err
}
Expand Down Expand Up @@ -352,6 +385,8 @@
}

var r PayloadReader
r.requestedOID = objectID
r.verifyChecksums = !prm.skipChecksumVerification
r.cancelCtxStream = cancel
r.stream = stream
r.singleMsgTimeout = c.streamTimeout
Expand All @@ -373,6 +408,13 @@
// PrmObjectHead groups optional parameters of ObjectHead operation.
type PrmObjectHead struct {
prmObjectRead
skipChecksumVerification bool
}

// SkipChecksumVerification allows to skip verification of received header
// against object ID.
func (x *PrmObjectHead) SkipChecksumVerification() {
x.skipChecksumVerification = true
}

// ObjectHead reads object header through a remote server using NeoFS API protocol.
Expand Down Expand Up @@ -450,11 +492,6 @@
return nil, err
}

if err = neofscrypto.VerifyResponseWithBuffer[*protoobject.HeadResponse_Body](resp, *buf); err != nil {
err = fmt.Errorf("%w: %w", errResponseSignatures, err)
return nil, err
}

if err = apistatus.ToError(resp.GetMetaHeader().GetStatus()); err != nil {
return nil, err
}
Expand Down Expand Up @@ -496,6 +533,14 @@
}); err != nil {
return nil, fmt.Errorf("invalid header response: %w", err)
}

if !prm.skipChecksumVerification {
hb := neofsproto.MarshalMessage(v.Header.Header)
if oid.NewFromObjectHeaderBinary(hb) != objectID {
return nil, errors.New("received header mismatches ID")
}
}

return &obj, nil
}
}
Expand Down
Loading
Loading