From c214d4d7633911185191c1fd281c0663f92b0f5c Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Mon, 17 Aug 2020 20:23:58 +0300 Subject: [PATCH] Add stable marshal for service package Signed-off-by: Alex Vanin --- v2/service/marshal.go | 1118 ++++++++++++++++++++++++++++++++++++ v2/service/marshal_test.go | 401 +++++++++++++ v2/service/service.go | 68 +-- 3 files changed, 1537 insertions(+), 50 deletions(-) create mode 100644 v2/service/marshal.go create mode 100644 v2/service/marshal_test.go diff --git a/v2/service/marshal.go b/v2/service/marshal.go new file mode 100644 index 00000000..241b2921 --- /dev/null +++ b/v2/service/marshal.go @@ -0,0 +1,1118 @@ +package service + +import ( + "encoding/binary" + + "github.com/nspcc-dev/neofs-api-go/util/proto" +) + +const ( + signatureKeyField = 1 + signatureValueField = 2 + + versionMajorField = 1 + versionMinorField = 2 + + xheaderKeyField = 1 + xheaderValueField = 2 + + lifetimeExpirationField = 1 + lifetimeNotValidBeforeField = 2 + lifetimeIssuedAtField = 3 + + objectCtxVerbField = 1 + objectCtxAddressField = 2 + + sessionTokenBodyIDField = 1 + sessionTokenBodyOwnerField = 2 + sessionTokenBodyLifetimeField = 3 + sessionTokenBodyKeyField = 4 + sessionTokenBodyObjectCtxField = 5 + + sessionTokenBodyField = 1 + sessionTokenSignatureField = 2 + + bearerTokenBodyACLField = 1 + bearerTokenBodyOwnerField = 2 + bearerTokenBodyLifetimeField = 3 + + bearerTokenBodyField = 1 + bearerTokenSignatureField = 2 + + reqMetaHeaderVersionField = 1 + reqMetaHeaderEpochField = 2 + reqMetaHeaderTTLField = 3 + reqMetaHeaderXHeadersField = 4 + reqMetaHeaderSessionTokenField = 5 + reqMetaHeaderBearerTokenField = 6 + reqMetaHeaderOriginField = 7 + + reqVerifHeaderBodySignatureField = 1 + reqVerifHeaderMetaSignatureField = 2 + reqVerifHeaderOriginSignatureField = 3 + reqVerifHeaderOriginField = 4 + + respMetaHeaderVersionField = 1 + respMetaHeaderEpochField = 2 + respMetaHeaderTTLField = 3 + respMetaHeaderXHeadersField = 4 + respMetaHeaderOriginField = 5 + + respVerifHeaderBodySignatureField = 1 + respVerifHeaderMetaSignatureField = 2 + respVerifHeaderOriginSignatureField = 3 + respVerifHeaderOriginField = 4 +) + +func (s *Signature) StableMarshal(buf []byte) ([]byte, error) { + if s == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, s.StableSize()) + } + + var ( + offset, n int + err error + ) + + n, err = proto.BytesMarshal(signatureKeyField, buf, s.key) + if err != nil { + return nil, err + } + + offset += n + + _, err = proto.BytesMarshal(signatureValueField, buf[offset:], s.sign) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (s *Signature) StableSize() (size int) { + if s == nil { + return 0 + } + + size += proto.BytesSize(signatureKeyField, s.key) + size += proto.BytesSize(signatureValueField, s.sign) + + return size +} + +func (v *Version) StableMarshal(buf []byte) ([]byte, error) { + if v == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, v.StableSize()) + } + + var ( + offset, n int + err error + ) + + n, err = proto.UInt32Marshal(versionMajorField, buf, v.major) + if err != nil { + return nil, err + } + + offset += n + + _, err = proto.UInt32Marshal(versionMinorField, buf[offset:], v.minor) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (v *Version) StableSize() (size int) { + if v == nil { + return 0 + } + + size += proto.UInt32Size(versionMajorField, v.major) + size += proto.UInt32Size(versionMinorField, v.minor) + + return size +} + +func (x *XHeader) StableMarshal(buf []byte) ([]byte, error) { + if x == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, x.StableSize()) + } + + var ( + offset, n int + err error + ) + + n, err = proto.StringMarshal(xheaderKeyField, buf, x.key) + if err != nil { + return nil, err + } + + offset += n + + _, err = proto.StringMarshal(xheaderValueField, buf[offset:], x.val) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (x *XHeader) StableSize() (size int) { + if x == nil { + return 0 + } + + size += proto.StringSize(xheaderKeyField, x.key) + size += proto.StringSize(xheaderValueField, x.val) + + return size +} + +func (l *TokenLifetime) StableMarshal(buf []byte) ([]byte, error) { + if l == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, l.StableSize()) + } + + var ( + offset, n int + err error + ) + + n, err = proto.UInt64Marshal(lifetimeExpirationField, buf, l.exp) + if err != nil { + return nil, err + } + + offset += n + + n, err = proto.UInt64Marshal(lifetimeNotValidBeforeField, buf[offset:], l.nbf) + if err != nil { + return nil, err + } + + offset += n + + _, err = proto.UInt64Marshal(lifetimeIssuedAtField, buf[offset:], l.iat) + if err != nil { + return nil, err + } + + return buf, nil +} + +func (l *TokenLifetime) StableSize() (size int) { + if l == nil { + return 0 + } + + size += proto.UInt64Size(lifetimeExpirationField, l.exp) + size += proto.UInt64Size(lifetimeNotValidBeforeField, l.nbf) + size += proto.UInt64Size(lifetimeIssuedAtField, l.iat) + + return size +} + +func (c *ObjectSessionContext) StableMarshal(buf []byte) ([]byte, error) { + if c == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, c.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + n, err = proto.EnumMarshal(objectCtxVerbField, buf, int32(c.verb)) + if err != nil { + return nil, err + } + + offset += n + + if c.addr != nil { + prefix, _ = proto.NestedStructurePrefix(objectCtxAddressField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = c.addr.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = c.addr.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (c *ObjectSessionContext) StableSize() (size int) { + if c == nil { + return 0 + } + + size += proto.EnumSize(objectCtxVerbField, int32(c.verb)) + + if c.addr != nil { + _, ln := proto.NestedStructurePrefix(objectCtxAddressField) + n := c.addr.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (t *SessionTokenBody) StableMarshal(buf []byte) ([]byte, error) { + if t == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, t.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + n, err = proto.BytesMarshal(sessionTokenBodyIDField, buf, t.id) + if err != nil { + return nil, err + } + + offset += n + + if t.ownerID != nil { + prefix, _ = proto.NestedStructurePrefix(sessionTokenBodyOwnerField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = t.ownerID.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = t.ownerID.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if t.lifetime != nil { + prefix, _ = proto.NestedStructurePrefix(sessionTokenBodyLifetimeField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = t.lifetime.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = t.lifetime.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + n, err = proto.BytesMarshal(sessionTokenBodyKeyField, buf[offset:], t.sessionKey) + if err != nil { + return nil, err + } + + offset += n + + if t.ctx != nil { + switch v := t.ctx.(type) { + case *ObjectSessionContext: + prefix, _ = proto.NestedStructurePrefix(sessionTokenBodyObjectCtxField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = v.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = v.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + default: + panic("cannot marshal unknown session token context") + } + } + + return buf, nil +} + +func (t *SessionTokenBody) StableSize() (size int) { + if t == nil { + return 0 + } + + size += proto.BytesSize(sessionTokenBodyIDField, t.id) + + if t.ownerID != nil { + _, ln := proto.NestedStructurePrefix(sessionTokenBodyOwnerField) + n := t.ownerID.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if t.lifetime != nil { + _, ln := proto.NestedStructurePrefix(sessionTokenBodyLifetimeField) + n := t.lifetime.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + size += proto.BytesSize(sessionTokenBodyKeyField, t.sessionKey) + + if t.ctx != nil { + switch v := t.ctx.(type) { + case *ObjectSessionContext: + _, ln := proto.NestedStructurePrefix(sessionTokenBodyObjectCtxField) + n := v.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + default: + panic("cannot marshal unknown session token context") + } + } + + return size +} + +func (t *SessionToken) StableMarshal(buf []byte) ([]byte, error) { + if t == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, t.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if t.body != nil { + prefix, _ = proto.NestedStructurePrefix(sessionTokenBodyField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = t.body.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = t.body.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if t.sig != nil { + prefix, _ = proto.NestedStructurePrefix(sessionTokenSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = t.sig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = t.sig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (t *SessionToken) StableSize() (size int) { + if t == nil { + return 0 + } + + if t.body != nil { + _, ln := proto.NestedStructurePrefix(sessionTokenBodyField) + n := t.body.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if t.sig != nil { + _, ln := proto.NestedStructurePrefix(sessionTokenSignatureField) + n := t.sig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (bt *BearerTokenBody) StableMarshal(buf []byte) ([]byte, error) { + if bt == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, bt.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if bt.eacl != nil { + prefix, _ = proto.NestedStructurePrefix(bearerTokenBodyACLField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = bt.eacl.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = bt.eacl.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if bt.ownerID != nil { + prefix, _ = proto.NestedStructurePrefix(bearerTokenBodyOwnerField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = bt.ownerID.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = bt.ownerID.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if bt.lifetime != nil { + prefix, _ = proto.NestedStructurePrefix(bearerTokenBodyLifetimeField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = bt.lifetime.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = bt.lifetime.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (bt *BearerTokenBody) StableSize() (size int) { + if bt == nil { + return 0 + } + + if bt.eacl != nil { + _, ln := proto.NestedStructurePrefix(bearerTokenBodyACLField) + n := bt.eacl.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if bt.ownerID != nil { + _, ln := proto.NestedStructurePrefix(bearerTokenBodyOwnerField) + n := bt.ownerID.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if bt.lifetime != nil { + _, ln := proto.NestedStructurePrefix(bearerTokenBodyLifetimeField) + n := bt.lifetime.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (bt *BearerToken) StableMarshal(buf []byte) ([]byte, error) { + if bt == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, bt.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if bt.body != nil { + prefix, _ = proto.NestedStructurePrefix(bearerTokenBodyField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = bt.body.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = bt.body.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if bt.sig != nil { + prefix, _ = proto.NestedStructurePrefix(bearerTokenSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = bt.sig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = bt.sig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (bt *BearerToken) StableSize() (size int) { + if bt == nil { + return 0 + } + + if bt.body != nil { + _, ln := proto.NestedStructurePrefix(bearerTokenBodyField) + n := bt.body.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if bt.sig != nil { + _, ln := proto.NestedStructurePrefix(bearerTokenSignatureField) + n := bt.sig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (r *RequestMetaHeader) StableMarshal(buf []byte) ([]byte, error) { + if r == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if r.version != nil { + prefix, _ = proto.NestedStructurePrefix(reqMetaHeaderVersionField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.version.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.version.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + n, err = proto.UInt64Marshal(reqMetaHeaderEpochField, buf[offset:], r.epoch) + if err != nil { + return nil, err + } + + offset += n + + n, err = proto.UInt32Marshal(reqMetaHeaderTTLField, buf[offset:], r.ttl) + if err != nil { + return nil, err + } + + offset += n + + prefix, _ = proto.NestedStructurePrefix(reqMetaHeaderXHeadersField) + + for i := range r.xHeaders { + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.xHeaders[i].StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.xHeaders[i].StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.sessionToken != nil { + prefix, _ = proto.NestedStructurePrefix(reqMetaHeaderSessionTokenField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.sessionToken.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.sessionToken.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.bearerToken != nil { + prefix, _ = proto.NestedStructurePrefix(reqMetaHeaderBearerTokenField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.bearerToken.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.bearerToken.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.origin != nil { + prefix, _ = proto.NestedStructurePrefix(reqMetaHeaderOriginField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.origin.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.origin.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (r *RequestMetaHeader) StableSize() (size int) { + if r == nil { + return 0 + } + + if r.version != nil { + _, ln := proto.NestedStructurePrefix(reqMetaHeaderVersionField) + n := r.version.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + size += proto.UInt64Size(reqMetaHeaderEpochField, r.epoch) + size += proto.UInt32Size(reqMetaHeaderTTLField, r.ttl) + + _, ln := proto.NestedStructurePrefix(reqMetaHeaderXHeadersField) + + for i := range r.xHeaders { + n := r.xHeaders[i].StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.sessionToken != nil { + _, ln := proto.NestedStructurePrefix(reqMetaHeaderSessionTokenField) + n := r.sessionToken.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.bearerToken != nil { + _, ln := proto.NestedStructurePrefix(reqMetaHeaderBearerTokenField) + n := r.bearerToken.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.origin != nil { + _, ln := proto.NestedStructurePrefix(reqMetaHeaderOriginField) + n := r.origin.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (r *RequestVerificationHeader) StableMarshal(buf []byte) ([]byte, error) { + if r == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if r.bodySig != nil { + prefix, _ = proto.NestedStructurePrefix(reqVerifHeaderBodySignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.bodySig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.bodySig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.metaSig != nil { + prefix, _ = proto.NestedStructurePrefix(reqVerifHeaderMetaSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.metaSig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.metaSig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.originSig != nil { + prefix, _ = proto.NestedStructurePrefix(reqVerifHeaderOriginSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.originSig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.originSig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.origin != nil { + prefix, _ = proto.NestedStructurePrefix(reqVerifHeaderOriginField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.origin.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.origin.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (r *RequestVerificationHeader) StableSize() (size int) { + if r == nil { + return 0 + } + + if r.bodySig != nil { + _, ln := proto.NestedStructurePrefix(reqVerifHeaderBodySignatureField) + n := r.bodySig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.metaSig != nil { + _, ln := proto.NestedStructurePrefix(reqVerifHeaderMetaSignatureField) + n := r.metaSig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.originSig != nil { + _, ln := proto.NestedStructurePrefix(reqVerifHeaderOriginSignatureField) + n := r.originSig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.origin != nil { + _, ln := proto.NestedStructurePrefix(reqVerifHeaderOriginField) + n := r.origin.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (r *ResponseMetaHeader) StableMarshal(buf []byte) ([]byte, error) { + if r == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if r.version != nil { + prefix, _ = proto.NestedStructurePrefix(respMetaHeaderVersionField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.version.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.version.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + n, err = proto.UInt64Marshal(respMetaHeaderEpochField, buf[offset:], r.epoch) + if err != nil { + return nil, err + } + + offset += n + + n, err = proto.UInt32Marshal(respMetaHeaderTTLField, buf[offset:], r.ttl) + if err != nil { + return nil, err + } + + offset += n + + prefix, _ = proto.NestedStructurePrefix(respMetaHeaderXHeadersField) + + for i := range r.xHeaders { + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.xHeaders[i].StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.xHeaders[i].StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.origin != nil { + prefix, _ = proto.NestedStructurePrefix(respMetaHeaderOriginField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.origin.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.origin.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (r *ResponseMetaHeader) StableSize() (size int) { + if r == nil { + return 0 + } + + if r.version != nil { + _, ln := proto.NestedStructurePrefix(respMetaHeaderVersionField) + n := r.version.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + size += proto.UInt64Size(respMetaHeaderEpochField, r.epoch) + size += proto.UInt32Size(respMetaHeaderTTLField, r.ttl) + + _, ln := proto.NestedStructurePrefix(respMetaHeaderXHeadersField) + + for i := range r.xHeaders { + n := r.xHeaders[i].StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.origin != nil { + _, ln := proto.NestedStructurePrefix(respMetaHeaderOriginField) + n := r.origin.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} + +func (r *ResponseVerificationHeader) StableMarshal(buf []byte) ([]byte, error) { + if r == nil { + return []byte{}, nil + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var ( + offset, n int + prefix uint64 + err error + ) + + if r.bodySig != nil { + prefix, _ = proto.NestedStructurePrefix(respVerifHeaderBodySignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.bodySig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.bodySig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.metaSig != nil { + prefix, _ = proto.NestedStructurePrefix(respVerifHeaderMetaSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.metaSig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.metaSig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.originSig != nil { + prefix, _ = proto.NestedStructurePrefix(respVerifHeaderOriginSignatureField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.originSig.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.originSig.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + + offset += n + } + + if r.origin != nil { + prefix, _ = proto.NestedStructurePrefix(respVerifHeaderOriginField) + offset += binary.PutUvarint(buf[offset:], prefix) + + n = r.origin.StableSize() + offset += binary.PutUvarint(buf[offset:], uint64(n)) + + _, err = r.origin.StableMarshal(buf[offset:]) + if err != nil { + return nil, err + + } + } + + return buf, nil +} + +func (r *ResponseVerificationHeader) StableSize() (size int) { + if r == nil { + return 0 + } + + if r.bodySig != nil { + _, ln := proto.NestedStructurePrefix(respVerifHeaderBodySignatureField) + n := r.bodySig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.metaSig != nil { + _, ln := proto.NestedStructurePrefix(respVerifHeaderMetaSignatureField) + n := r.metaSig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.originSig != nil { + _, ln := proto.NestedStructurePrefix(respVerifHeaderOriginSignatureField) + n := r.originSig.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + if r.origin != nil { + _, ln := proto.NestedStructurePrefix(respVerifHeaderOriginField) + n := r.origin.StableSize() + size += ln + proto.VarUIntSize(uint64(n)) + n + } + + return size +} diff --git a/v2/service/marshal_test.go b/v2/service/marshal_test.go new file mode 100644 index 00000000..35ad8fbd --- /dev/null +++ b/v2/service/marshal_test.go @@ -0,0 +1,401 @@ +package service_test + +import ( + "fmt" + "testing" + + "github.com/nspcc-dev/neofs-api-go/v2/acl" + "github.com/nspcc-dev/neofs-api-go/v2/refs" + "github.com/nspcc-dev/neofs-api-go/v2/service" + grpc "github.com/nspcc-dev/neofs-api-go/v2/service/grpc" + "github.com/stretchr/testify/require" +) + +func TestSignature_StableMarshal(t *testing.T) { + signatureFrom := generateSignature("Public Key", "Signature") + transport := new(grpc.Signature) + + t.Run("non empty", func(t *testing.T) { + wire, err := signatureFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + signatureTo := service.SignatureFromGRPCMessage(transport) + require.Equal(t, signatureFrom, signatureTo) + }) +} + +func TestVersion_StableMarshal(t *testing.T) { + versionFrom := generateVersion(2, 0) + transport := new(grpc.Version) + + t.Run("non empty", func(t *testing.T) { + wire, err := versionFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + versionTo := service.VersionFromGRPCMessage(transport) + require.Equal(t, versionFrom, versionTo) + }) +} + +func TestXHeader_StableMarshal(t *testing.T) { + xheaderFrom := generateXHeader("X-Header-Key", "X-Header-Value") + transport := new(grpc.XHeader) + + t.Run("non empty", func(t *testing.T) { + wire, err := xheaderFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + xheaderTo := service.XHeaderFromGRPCMessage(transport) + require.Equal(t, xheaderFrom, xheaderTo) + }) +} + +func TestTokenLifetime_StableMarshal(t *testing.T) { + lifetimeFrom := generateLifetime(10, 20, 30) + transport := new(grpc.TokenLifetime) + + t.Run("non empty", func(t *testing.T) { + wire, err := lifetimeFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + lifetimeTo := service.TokenLifetimeFromGRPCMessage(transport) + require.Equal(t, lifetimeFrom, lifetimeTo) + }) +} + +func TestObjectSessionContext_StableMarshal(t *testing.T) { + objectCtxFrom := generateObjectCtx("Object ID") + transport := new(grpc.ObjectServiceContext) + + t.Run("non empty", func(t *testing.T) { + wire, err := objectCtxFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + objectCtxTo := service.ObjectSessionContextFromGRPCMessage(transport) + require.Equal(t, objectCtxFrom, objectCtxTo) + }) +} + +func TestSessionTokenBody_StableMarshal(t *testing.T) { + sessionTokenBodyFrom := generateSessionTokenBody("Session Token Body") + transport := new(grpc.SessionToken_Body) + + t.Run("non empty", func(t *testing.T) { + wire, err := sessionTokenBodyFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + sessionTokenBodyTo := service.SessionTokenBodyFromGRPCMessage(transport) + require.Equal(t, sessionTokenBodyFrom, sessionTokenBodyTo) + }) +} + +func TestSessionToken_StableMarshal(t *testing.T) { + sessionTokenFrom := generateSessionToken("Session Token") + transport := new(grpc.SessionToken) + + t.Run("non empty", func(t *testing.T) { + wire, err := sessionTokenFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + sessionTokenTo := service.SessionTokenFromGRPCMessage(transport) + require.Equal(t, sessionTokenFrom, sessionTokenTo) + }) +} + +func TestBearerTokenBody_StableMarshal(t *testing.T) { + bearerTokenBodyFrom := generateBearerTokenBody("Bearer Token Body") + transport := new(grpc.BearerToken_Body) + + t.Run("non empty", func(t *testing.T) { + wire, err := bearerTokenBodyFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + bearerTokenBodyTo := service.BearerTokenBodyFromGRPCMessage(transport) + require.Equal(t, bearerTokenBodyFrom, bearerTokenBodyTo) + }) +} + +func TestBearerToken_StableMarshal(t *testing.T) { + bearerTokenFrom := generateBearerToken("Bearer Token") + transport := new(grpc.BearerToken) + + t.Run("non empty", func(t *testing.T) { + wire, err := bearerTokenFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + bearerTokenTo := service.BearerTokenFromGRPCMessage(transport) + require.Equal(t, bearerTokenFrom, bearerTokenTo) + }) +} + +func TestRequestMetaHeader_StableMarshal(t *testing.T) { + metaHeaderOrigin := generateRequestMetaHeader(10, "Bearer One", "Session One") + metaHeaderFrom := generateRequestMetaHeader(20, "Bearer Two", "Session Two") + metaHeaderFrom.SetOrigin(metaHeaderOrigin) + transport := new(grpc.RequestMetaHeader) + + t.Run("non empty", func(t *testing.T) { + wire, err := metaHeaderFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + metaHeaderTo := service.RequestMetaHeaderFromGRPCMessage(transport) + require.Equal(t, metaHeaderFrom, metaHeaderTo) + }) +} + +func TestRequestVerificationHeader_StableMarshal(t *testing.T) { + verifHeaderOrigin := generateRequestVerificationHeader("Key", "Inside") + verifHeaderFrom := generateRequestVerificationHeader("Value", "Outside") + verifHeaderFrom.SetOrigin(verifHeaderOrigin) + transport := new(grpc.RequestVerificationHeader) + + t.Run("non empty", func(t *testing.T) { + wire, err := verifHeaderFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + verifHeaderTo := service.RequestVerificationHeaderFromGRPCMessage(transport) + require.Equal(t, verifHeaderFrom, verifHeaderTo) + }) +} + +func TestResponseMetaHeader_StableMarshal(t *testing.T) { + metaHeaderOrigin := generateResponseMetaHeader(10) + metaHeaderFrom := generateResponseMetaHeader(20) + metaHeaderFrom.SetOrigin(metaHeaderOrigin) + transport := new(grpc.ResponseMetaHeader) + + t.Run("non empty", func(t *testing.T) { + wire, err := metaHeaderFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + metaHeaderTo := service.ResponseMetaHeaderFromGRPCMessage(transport) + require.Equal(t, metaHeaderFrom, metaHeaderTo) + }) +} + +func TestResponseVerificationHeader_StableMarshal(t *testing.T) { + verifHeaderOrigin := generateResponseVerificationHeader("Key", "Inside") + verifHeaderFrom := generateResponseVerificationHeader("Value", "Outside") + verifHeaderFrom.SetOrigin(verifHeaderOrigin) + transport := new(grpc.ResponseVerificationHeader) + + t.Run("non empty", func(t *testing.T) { + wire, err := verifHeaderFrom.StableMarshal(nil) + require.NoError(t, err) + + err = transport.Unmarshal(wire) + require.NoError(t, err) + + verifHeaderTo := service.ResponseVerificationHeaderFromGRPCMessage(transport) + require.Equal(t, verifHeaderFrom, verifHeaderTo) + }) +} + +func generateSignature(k, v string) *service.Signature { + sig := new(service.Signature) + sig.SetKey([]byte(k)) + sig.SetSign([]byte(v)) + + return sig +} + +func generateVersion(maj, min uint32) *service.Version { + version := new(service.Version) + version.SetMajor(maj) + version.SetMinor(min) + + return version +} + +func generateXHeader(k, v string) *service.XHeader { + xheader := new(service.XHeader) + xheader.SetKey(k) + xheader.SetValue(v) + + return xheader +} + +func generateLifetime(exp, nbf, iat uint64) *service.TokenLifetime { + lifetime := new(service.TokenLifetime) + lifetime.SetExp(exp) + lifetime.SetNbf(nbf) + lifetime.SetIat(iat) + + return lifetime +} + +func generateObjectCtx(id string) *service.ObjectSessionContext { + objectCtx := new(service.ObjectSessionContext) + objectCtx.SetVerb(service.ObjectVerbPut) + + cid := new(refs.ContainerID) + cid.SetValue([]byte("ContainerID")) + + oid := new(refs.ObjectID) + oid.SetValue([]byte(id)) + + addr := new(refs.Address) + addr.SetContainerID(cid) + addr.SetObjectID(oid) + + objectCtx.SetAddress(addr) + + return objectCtx +} + +func generateEACL(n int, k, v string) *acl.Table { + target := new(acl.TargetInfo) + target.SetTarget(acl.TargetUser) + + keys := make([][]byte, n) + + for i := 0; i < n; i++ { + s := fmt.Sprintf("Public Key %d", i+1) + keys[i] = []byte(s) + } + + filter := new(acl.HeaderFilter) + filter.SetHeaderType(acl.HeaderTypeObject) + filter.SetMatchType(acl.MatchTypeStringEqual) + filter.SetName(k) + filter.SetValue(v) + + record := new(acl.Record) + record.SetOperation(acl.OperationHead) + record.SetAction(acl.ActionDeny) + record.SetTargets([]*acl.TargetInfo{target}) + record.SetFilters([]*acl.HeaderFilter{filter}) + + table := new(acl.Table) + cid := new(refs.ContainerID) + cid.SetValue([]byte("Container ID")) + + table.SetContainerID(cid) + table.SetRecords([]*acl.Record{record}) + + return table +} + +func generateSessionTokenBody(id string) *service.SessionTokenBody { + owner := new(refs.OwnerID) + owner.SetValue([]byte("Owner ID")) + + tokenBody := new(service.SessionTokenBody) + tokenBody.SetID([]byte(id)) + tokenBody.SetOwnerID(owner) + tokenBody.SetSessionKey([]byte(id)) + tokenBody.SetLifetime(generateLifetime(1, 2, 3)) + tokenBody.SetContext(generateObjectCtx(id)) + + return tokenBody +} + +func generateSessionToken(id string) *service.SessionToken { + sessionToken := new(service.SessionToken) + sessionToken.SetBody(generateSessionTokenBody(id)) + sessionToken.SetSignature(generateSignature("id", id)) + + return sessionToken +} + +func generateBearerTokenBody(id string) *service.BearerTokenBody { + owner := new(refs.OwnerID) + owner.SetValue([]byte(id)) + + tokenBody := new(service.BearerTokenBody) + tokenBody.SetOwnerID(owner) + tokenBody.SetLifetime(generateLifetime(1, 2, 3)) + tokenBody.SetEACL(generateEACL(10, "id", id)) + + return tokenBody +} + +func generateBearerToken(id string) *service.BearerToken { + bearerToken := new(service.BearerToken) + bearerToken.SetBody(generateBearerTokenBody(id)) + bearerToken.SetSignature(generateSignature("id", id)) + + return bearerToken +} + +func generateRequestMetaHeader(n int, b, s string) *service.RequestMetaHeader { + reqMetaHeader := new(service.RequestMetaHeader) + reqMetaHeader.SetVersion(generateVersion(2, 0)) + reqMetaHeader.SetEpoch(uint64(n)) + reqMetaHeader.SetTTL(uint32(n)) + reqMetaHeader.SetXHeaders([]*service.XHeader{ + generateXHeader("key-one", "val-one"), + generateXHeader("key-two", "val-two"), + }) + reqMetaHeader.SetBearerToken(generateBearerToken(b)) + reqMetaHeader.SetSessionToken(generateSessionToken(s)) + + return reqMetaHeader +} + +func generateRequestVerificationHeader(k, v string) *service.RequestVerificationHeader { + reqVerifHeader := new(service.RequestVerificationHeader) + reqVerifHeader.SetBodySignature(generateSignature(k+"body", v+"body")) + reqVerifHeader.SetMetaSignature(generateSignature(k+"meta", v+"meta")) + reqVerifHeader.SetOriginSignature(generateSignature(k+"orig", v+"orig")) + + return reqVerifHeader +} + +func generateResponseMetaHeader(n int) *service.ResponseMetaHeader { + respMetaHeader := new(service.ResponseMetaHeader) + respMetaHeader.SetVersion(generateVersion(2, 0)) + respMetaHeader.SetEpoch(uint64(n)) + respMetaHeader.SetTTL(uint32(n)) + respMetaHeader.SetXHeaders([]*service.XHeader{ + generateXHeader("key-one", "val-one"), + generateXHeader("key-two", "val-two"), + }) + + return respMetaHeader +} + +func generateResponseVerificationHeader(k, v string) *service.ResponseVerificationHeader { + respVerifHeader := new(service.ResponseVerificationHeader) + respVerifHeader.SetBodySignature(generateSignature(k+"body", v+"body")) + respVerifHeader.SetMetaSignature(generateSignature(k+"meta", v+"meta")) + respVerifHeader.SetOriginSignature(generateSignature(k+"orig", v+"orig")) + + return respVerifHeader +} diff --git a/v2/service/service.go b/v2/service/service.go index 61e33cb8..b40106ab 100644 --- a/v2/service/service.go +++ b/v2/service/service.go @@ -256,22 +256,6 @@ func (r *RequestVerificationHeader) SetOrigin(v *RequestVerificationHeader) { } } -func (r *RequestVerificationHeader) StableMarshal(buf []byte) ([]byte, error) { - if r == nil { - return nil, nil - } - - // TODO: do not use hack - _, err := RequestVerificationHeaderToGRPCMessage(r).MarshalTo(buf) - - return buf, err -} - -func (r *RequestVerificationHeader) StableSize() int { - // TODO: do not use hack - return RequestVerificationHeaderToGRPCMessage(r).Size() -} - func (r *RequestMetaHeader) GetVersion() *Version { if r != nil { return r.version @@ -370,61 +354,45 @@ func (r *RequestMetaHeader) SetOrigin(v *RequestMetaHeader) { } } -func (r *RequestMetaHeader) StableMarshal(buf []byte) ([]byte, error) { - if r == nil { - return nil, nil - } - - // TODO: do not use hack - _, err := RequestMetaHeaderToGRPCMessage(r).MarshalTo(buf) - - return buf, err -} - -func (r *RequestMetaHeader) StableSize() int { - // TODO: do not use hack - return RequestMetaHeaderToGRPCMessage(r).Size() -} - -func (tl *TokenLifetime) GetExp() uint64 { - if tl != nil { - return tl.exp +func (l *TokenLifetime) GetExp() uint64 { + if l != nil { + return l.exp } return 0 } -func (tl *TokenLifetime) SetExp(v uint64) { - if tl != nil { - tl.exp = v +func (l *TokenLifetime) SetExp(v uint64) { + if l != nil { + l.exp = v } } -func (tl *TokenLifetime) GetNbf() uint64 { - if tl != nil { - return tl.nbf +func (l *TokenLifetime) GetNbf() uint64 { + if l != nil { + return l.nbf } return 0 } -func (tl *TokenLifetime) SetNbf(v uint64) { - if tl != nil { - tl.nbf = v +func (l *TokenLifetime) SetNbf(v uint64) { + if l != nil { + l.nbf = v } } -func (tl *TokenLifetime) GetIat() uint64 { - if tl != nil { - return tl.iat +func (l *TokenLifetime) GetIat() uint64 { + if l != nil { + return l.iat } return 0 } -func (tl *TokenLifetime) SetIat(v uint64) { - if tl != nil { - tl.iat = v +func (l *TokenLifetime) SetIat(v uint64) { + if l != nil { + l.iat = v } }