package session import ( "crypto/ecdsa" "errors" "fmt" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" ) // Object represents token of the NeoFS Object session. A session is opened // between any two sides of the system, and implements a mechanism for transferring // the power of attorney of actions to another network member. The session has a // limited validity period, and applies to a strictly defined set of operations. // See methods for details. // // Object is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/session.Token // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. type Object struct { commonData verb ObjectVerb cnrSet bool cnr cid.ID objSet bool obj oid.ID } func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error { cObj, ok := c.(*session.ObjectSessionContext) if !ok || cObj == nil { return fmt.Errorf("invalid context %T", c) } addr := cObj.GetAddress() if checkFieldPresence && addr == nil { return errors.New("missing object address") } var err error cnr := addr.GetContainerID() if x.cnrSet = cnr != nil; x.cnrSet { err := x.cnr.ReadFromV2(*cnr) if err != nil { return fmt.Errorf("invalid container ID: %w", err) } } else if checkFieldPresence { return errors.New("missing container in object address") } obj := addr.GetObjectID() if x.objSet = obj != nil; x.objSet { err = x.obj.ReadFromV2(*obj) if err != nil { return fmt.Errorf("invalid object ID: %w", err) } } x.verb = ObjectVerb(cObj.GetVerb()) return nil } func (x *Object) readFromV2(m session.Token, checkFieldPresence bool) error { return x.commonData.readFromV2(m, checkFieldPresence, x.readContext) } // ReadFromV2 reads Object from the session.Token message. Checks if the // message conforms to NeoFS API V2 protocol. // // See also WriteToV2. func (x *Object) ReadFromV2(m session.Token) error { return x.readFromV2(m, true) } func (x Object) writeContext() session.TokenContext { var c session.ObjectSessionContext c.SetVerb(session.ObjectSessionVerb(x.verb)) if x.cnrSet || x.objSet { var addr refs.Address if x.cnrSet { var cnr refs.ContainerID x.cnr.WriteToV2(&cnr) addr.SetContainerID(&cnr) } if x.objSet { var obj refs.ObjectID x.obj.WriteToV2(&obj) addr.SetObjectID(&obj) } c.SetAddress(&addr) } return &c } // WriteToV2 writes Object to the session.Token message. // The message must not be nil. // // See also ReadFromV2. func (x Object) WriteToV2(m *session.Token) { x.writeToV2(m, x.writeContext) } // Marshal encodes Object into a binary format of the NeoFS API protocol // (Protocol Buffers with direct field order). // // See also Unmarshal. func (x Object) Marshal() []byte { var m session.Token x.WriteToV2(&m) return x.marshal(x.writeContext) } // Unmarshal decodes NeoFS API protocol binary format into the Object // (Protocol Buffers with direct field order). Returns an error describing // a format violation. // // See also Marshal. func (x *Object) Unmarshal(data []byte) error { return x.unmarshal(data, x.readContext) } // MarshalJSON encodes Object into a JSON format of the NeoFS API protocol // (Protocol Buffers JSON). // // See also UnmarshalJSON. func (x Object) MarshalJSON() ([]byte, error) { return x.marshalJSON(x.writeContext) } // UnmarshalJSON decodes NeoFS API protocol JSON format into the Object // (Protocol Buffers JSON). Returns an error describing a format violation. // // See also MarshalJSON. func (x *Object) UnmarshalJSON(data []byte) error { return x.unmarshalJSON(data, x.readContext) } // Sign calculates and writes signature of the Object data. // Returns signature calculation errors. // // Zero Object is unsigned. // // Note that any Object mutation is likely to break the signature, so it is // expected to be calculated as a final stage of Object formation. // // See also VerifySignature. func (x *Object) Sign(key ecdsa.PrivateKey) error { return x.sign(key, x.writeContext) } // VerifySignature checks if Object signature is presented and valid. // // Zero Object fails the check. // // See also Sign. func (x Object) VerifySignature() bool { // TODO: (#233) check owner<->key relation return x.verifySignature(x.writeContext) } // BindContainer binds the Object session to a given container. Each session // MUST be bound to exactly one container. // // See also AssertContainer. func (x *Object) BindContainer(cnr cid.ID) { x.cnr = cnr x.cnrSet = true } // AssertContainer checks if Object session bound to a given container. // // Zero Object isn't bound to any container which is incorrect according to // NeoFS API protocol. // // See also BindContainer. func (x Object) AssertContainer(cnr cid.ID) bool { return x.cnr.Equals(cnr) } // LimitByObject limits session scope to a given object from the container // to which Object session is bound. // // See also AssertObject. func (x *Object) LimitByObject(obj oid.ID) { x.obj = obj x.objSet = true } // AssertObject checks if Object session is applied to a given object. // // Zero Object is applied to all objects in the container. // // See also LimitByObject. func (x Object) AssertObject(obj oid.ID) bool { return !x.objSet || x.obj.Equals(obj) } // ObjectVerb enumerates object operations. type ObjectVerb int8 const ( _ ObjectVerb = iota VerbObjectPut // Put rpc VerbObjectGet // Get rpc VerbObjectHead // Head rpc VerbObjectSearch // Search rpc VerbObjectDelete // Delete rpc VerbObjectRange // GetRange rpc VerbObjectRangeHash // GetRangeHash rpc ) // ForVerb specifies the object operation of the session scope. Each // Object is related to the single operation. // // See also AssertVerb. func (x *Object) ForVerb(verb ObjectVerb) { x.verb = verb } // AssertVerb checks if Object relates to one of the given object operations. // // Zero Object relates to zero (unspecified) verb. // // See also ForVerb. func (x Object) AssertVerb(verbs ...ObjectVerb) bool { for i := range verbs { if verbs[i] == x.verb { return true } } return false } // ExpiredAt asserts "exp" claim. // // Zero Object is expired in any epoch. // // See also SetExp. func (x Object) ExpiredAt(epoch uint64) bool { return x.expiredAt(epoch) }