forked from TrueCloudLab/frostfs-api-go
[#140] sdk/object: Refactor object types
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
e40995b5d4
commit
6ce70d4a18
4 changed files with 574 additions and 236 deletions
|
@ -1,21 +1,10 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
||||
"github.com/nspcc-dev/neofs-api-go/util/signature"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||
signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Object represents NeoFS object that provides
|
||||
// Object represents v2-compatible NeoFS object that provides
|
||||
// a convenient interface for working in isolation
|
||||
// from the internal structure of an object.
|
||||
//
|
||||
|
@ -23,198 +12,28 @@ import (
|
|||
// mode as a reflection of the immutability of objects
|
||||
// in the system.
|
||||
type Object struct {
|
||||
rwObject
|
||||
*rwObject
|
||||
}
|
||||
|
||||
type rwObject struct {
|
||||
fin bool
|
||||
|
||||
id *ID
|
||||
|
||||
key, sig []byte
|
||||
|
||||
cid *container.ID
|
||||
|
||||
ownerID *owner.ID
|
||||
|
||||
payloadChecksum *refs.Checksum
|
||||
|
||||
payload []byte
|
||||
|
||||
// TODO: add other fields
|
||||
}
|
||||
|
||||
// Verify checks if object structure is correct.
|
||||
func (o *Object) Verify() error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
hdr := o.v2Header()
|
||||
|
||||
data, err := hdr.StableMarshal(nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not marshal header")
|
||||
}
|
||||
|
||||
hdrChecksum := sha256.Sum256(data)
|
||||
|
||||
if !bytes.Equal(hdrChecksum[:], o.id.ToV2().GetValue()) {
|
||||
return errors.New("invalid object identifier")
|
||||
}
|
||||
|
||||
if err := signature.VerifyDataWithSource(
|
||||
signatureV2.StableMarshalerWrapper{
|
||||
SM: o.id.ToV2(),
|
||||
},
|
||||
func() (key, sig []byte) {
|
||||
return o.key, o.sig
|
||||
},
|
||||
); err != nil {
|
||||
return errors.Wrap(err, "invalid object ID signature")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPayload returns object payload bytes.
|
||||
func (o *Object) GetPayload() []byte {
|
||||
if o != nil {
|
||||
return o.payload
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CutPayload copies object fields w/o payload.
|
||||
func (o *Object) CutPayload() *Object {
|
||||
if o != nil {
|
||||
return &Object{
|
||||
rwObject: rwObject{
|
||||
fin: o.fin,
|
||||
id: o.id,
|
||||
key: o.key,
|
||||
sig: o.sig,
|
||||
cid: o.cid,
|
||||
ownerID: o.ownerID,
|
||||
payloadChecksum: o.payloadChecksum,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *rwObject) v2Header() *object.Header {
|
||||
hV2 := new(object.Header)
|
||||
hV2.SetContainerID(o.cid.ToV2())
|
||||
hV2.SetOwnerID(o.ownerID.ToV2())
|
||||
hV2.SetPayloadHash(o.payloadChecksum)
|
||||
// TODO: set other fields
|
||||
|
||||
return hV2
|
||||
}
|
||||
|
||||
func (o *rwObject) complete(key *ecdsa.PrivateKey) (*object.Header, error) {
|
||||
hdr := o.v2Header()
|
||||
|
||||
hdrData, err := hdr.StableMarshal(nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not marshal header")
|
||||
}
|
||||
|
||||
o.id = new(ID)
|
||||
o.id.SetSHA256(sha256.Sum256(hdrData))
|
||||
|
||||
if err := signature.SignDataWithHandler(
|
||||
key,
|
||||
signatureV2.StableMarshalerWrapper{
|
||||
SM: o.id.ToV2(),
|
||||
},
|
||||
func(key []byte, sig []byte) {
|
||||
o.key, o.sig = key, sig
|
||||
},
|
||||
); err != nil {
|
||||
return nil, errors.Wrap(err, "could sign object identifier")
|
||||
}
|
||||
|
||||
o.fin = true
|
||||
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// ToV2 calculates object identifier, signs structure and converts
|
||||
// it to v2 Object message.
|
||||
func (o *rwObject) ToV2(key *ecdsa.PrivateKey) (*object.Object, error) {
|
||||
if o == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var (
|
||||
hdr *object.Header
|
||||
err error
|
||||
)
|
||||
|
||||
if !o.fin {
|
||||
if key == nil {
|
||||
return nil, errors.Wrap(crypto.ErrEmptyPrivateKey, "could complete the object")
|
||||
}
|
||||
|
||||
if hdr, err = o.complete(key); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not complete the object")
|
||||
}
|
||||
} else {
|
||||
hdr = o.v2Header()
|
||||
}
|
||||
|
||||
obj := new(object.Object)
|
||||
obj.SetObjectID(o.id.ToV2())
|
||||
obj.SetHeader(hdr)
|
||||
obj.SetPayload(o.payload)
|
||||
|
||||
sig := new(refs.Signature)
|
||||
sig.SetKey(o.key)
|
||||
sig.SetSign(o.sig)
|
||||
obj.SetSignature(sig)
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// FromV2 converts v2 Object message to Object instance.
|
||||
//
|
||||
// Returns any error encountered which prevented the
|
||||
// recovery of object data from the message.
|
||||
func FromV2(oV2 *object.Object) (*Object, error) {
|
||||
if oV2 == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
hdr := oV2.GetHeader()
|
||||
|
||||
// TODO: convert other fields
|
||||
|
||||
sig := oV2.GetSignature()
|
||||
|
||||
// NewFromV2 wraps v2 Object message to Object.
|
||||
func NewFromV2(oV2 *object.Object) *Object {
|
||||
return &Object{
|
||||
rwObject: rwObject{
|
||||
fin: true,
|
||||
id: NewIDFromV2(oV2.GetObjectID()),
|
||||
key: sig.GetKey(),
|
||||
sig: sig.GetSign(),
|
||||
cid: container.NewIDFromV2(hdr.GetContainerID()),
|
||||
ownerID: owner.NewIDFromV2(hdr.GetOwnerID()),
|
||||
payloadChecksum: hdr.GetPayloadHash(),
|
||||
payload: oV2.GetPayload(),
|
||||
},
|
||||
}, nil
|
||||
rwObject: (*rwObject)(oV2),
|
||||
}
|
||||
}
|
||||
|
||||
// FromBytes restores Object from a binary representation.
|
||||
func FromBytes(data []byte) (*Object, error) {
|
||||
oV2 := new(object.Object)
|
||||
if err := oV2.StableUnmarshal(data); err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal object")
|
||||
// New creates and initializes blank Object.
|
||||
//
|
||||
// Works similar as NewFromV2(new(Object)).
|
||||
func New() *Object {
|
||||
return NewFromV2(initObjectRecursive())
|
||||
}
|
||||
|
||||
// ToV2 converts Object to v2 Object message.
|
||||
func (o *Object) ToV2() *object.Object {
|
||||
if o != nil {
|
||||
return (*object.Object)(o.rwObject)
|
||||
}
|
||||
|
||||
return FromV2(oV2)
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue