git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/session/object.go (about)

     1  package session
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
     9  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
    10  	cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
    11  	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
    12  )
    13  
    14  // Object represents token of the FrostFS Object session. A session is opened
    15  // between any two sides of the system, and implements a mechanism for transferring
    16  // the power of attorney of actions to another network member. The session has a
    17  // limited validity period, and applies to a strictly defined set of operations.
    18  // See methods for details.
    19  //
    20  // Object is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token
    21  // message. See ReadFromV2 / WriteToV2 methods.
    22  //
    23  // Instances can be created using built-in var declaration.
    24  type Object struct {
    25  	commonData
    26  
    27  	verb ObjectVerb
    28  
    29  	cnrSet bool
    30  	cnr    cid.ID
    31  
    32  	objs []oid.ID
    33  }
    34  
    35  func (x *Object) readContext(c session.TokenContext, checkFieldPresence bool) error {
    36  	cObj, ok := c.(*session.ObjectSessionContext)
    37  	if !ok || cObj == nil {
    38  		return fmt.Errorf("invalid context %T", c)
    39  	}
    40  
    41  	var err error
    42  
    43  	cnr := cObj.GetContainer()
    44  	if x.cnrSet = cnr != nil; x.cnrSet {
    45  		err := x.cnr.ReadFromV2(*cnr)
    46  		if err != nil {
    47  			return fmt.Errorf("invalid container ID: %w", err)
    48  		}
    49  	} else if checkFieldPresence {
    50  		return errors.New("missing target container")
    51  	}
    52  
    53  	objs := cObj.GetObjects()
    54  	if objs != nil {
    55  		x.objs = make([]oid.ID, len(objs))
    56  
    57  		for i := range objs {
    58  			err = x.objs[i].ReadFromV2(objs[i])
    59  			if err != nil {
    60  				return fmt.Errorf("invalid target object: %w", err)
    61  			}
    62  		}
    63  	} else {
    64  		x.objs = nil
    65  	}
    66  
    67  	x.verb = ObjectVerb(cObj.GetVerb())
    68  
    69  	return nil
    70  }
    71  
    72  func (x *Object) readFromV2(m session.Token, checkFieldPresence bool) error {
    73  	return x.commonData.readFromV2(m, checkFieldPresence, x.readContext)
    74  }
    75  
    76  // ReadFromV2 reads Object from the session.Token message. Checks if the
    77  // message conforms to FrostFS API V2 protocol.
    78  //
    79  // See also WriteToV2.
    80  func (x *Object) ReadFromV2(m session.Token) error {
    81  	return x.readFromV2(m, true)
    82  }
    83  
    84  func (x Object) writeContext() session.TokenContext {
    85  	var c session.ObjectSessionContext
    86  	c.SetVerb(session.ObjectSessionVerb(x.verb))
    87  
    88  	if x.cnrSet || len(x.objs) > 0 {
    89  		var cnr *refs.ContainerID
    90  
    91  		if x.cnrSet {
    92  			cnr = new(refs.ContainerID)
    93  			x.cnr.WriteToV2(cnr)
    94  		}
    95  
    96  		var objs []refs.ObjectID
    97  
    98  		if x.objs != nil {
    99  			objs = make([]refs.ObjectID, len(x.objs))
   100  
   101  			for i := range x.objs {
   102  				x.objs[i].WriteToV2(&objs[i])
   103  			}
   104  		}
   105  
   106  		c.SetTarget(cnr, objs...)
   107  	}
   108  
   109  	return &c
   110  }
   111  
   112  // WriteToV2 writes Object to the session.Token message.
   113  // The message must not be nil.
   114  //
   115  // See also ReadFromV2.
   116  func (x Object) WriteToV2(m *session.Token) {
   117  	x.writeToV2(m, x.writeContext)
   118  }
   119  
   120  // Marshal encodes Object into a binary format of the FrostFS API protocol
   121  // (Protocol Buffers with direct field order).
   122  //
   123  // See also Unmarshal.
   124  func (x Object) Marshal() []byte {
   125  	var m session.Token
   126  	x.WriteToV2(&m)
   127  
   128  	return x.marshal(x.writeContext)
   129  }
   130  
   131  // Unmarshal decodes FrostFS API protocol binary format into the Object
   132  // (Protocol Buffers with direct field order). Returns an error describing
   133  // a format violation.
   134  //
   135  // See also Marshal.
   136  func (x *Object) Unmarshal(data []byte) error {
   137  	return x.unmarshal(data, x.readContext)
   138  }
   139  
   140  // MarshalJSON encodes Object into a JSON format of the FrostFS API protocol
   141  // (Protocol Buffers JSON).
   142  //
   143  // See also UnmarshalJSON.
   144  func (x Object) MarshalJSON() ([]byte, error) {
   145  	return x.marshalJSON(x.writeContext)
   146  }
   147  
   148  // UnmarshalJSON decodes FrostFS API protocol JSON format into the Object
   149  // (Protocol Buffers JSON). Returns an error describing a format violation.
   150  //
   151  // See also MarshalJSON.
   152  func (x *Object) UnmarshalJSON(data []byte) error {
   153  	return x.unmarshalJSON(data, x.readContext)
   154  }
   155  
   156  // Sign calculates and writes signature of the Object data.
   157  // Returns signature calculation errors.
   158  //
   159  // Zero Object is unsigned.
   160  //
   161  // Note that any Object mutation is likely to break the signature, so it is
   162  // expected to be calculated as a final stage of Object formation.
   163  //
   164  // See also VerifySignature.
   165  func (x *Object) Sign(key ecdsa.PrivateKey) error {
   166  	return x.sign(key, x.writeContext)
   167  }
   168  
   169  // VerifySignature checks if Object signature is presented and valid.
   170  //
   171  // Zero Object fails the check.
   172  //
   173  // See also Sign.
   174  func (x Object) VerifySignature() bool {
   175  	// TODO: (#233) check owner<->key relation
   176  	return x.verifySignature(x.writeContext)
   177  }
   178  
   179  // BindContainer binds the Object session to a given container. Each session
   180  // MUST be bound to exactly one container.
   181  //
   182  // See also AssertContainer.
   183  func (x *Object) BindContainer(cnr cid.ID) {
   184  	x.cnr = cnr
   185  	x.cnrSet = true
   186  }
   187  
   188  // AssertContainer checks if Object session bound to a given container.
   189  //
   190  // Zero Object isn't bound to any container which is incorrect according to
   191  // FrostFS API protocol.
   192  //
   193  // See also BindContainer.
   194  func (x Object) AssertContainer(cnr cid.ID) bool {
   195  	return x.cnr.Equals(cnr)
   196  }
   197  
   198  // LimitByObjects limits session scope to the given objects from the container
   199  // to which Object session is bound.
   200  //
   201  // Argument MUST NOT be mutated, make a copy first.
   202  //
   203  // See also AssertObject.
   204  func (x *Object) LimitByObjects(objs ...oid.ID) {
   205  	x.objs = objs
   206  }
   207  
   208  // AssertObject checks if Object session is applied to a given object.
   209  //
   210  // Zero Object is applied to all objects in the container.
   211  //
   212  // See also LimitByObjects.
   213  func (x Object) AssertObject(obj oid.ID) bool {
   214  	if len(x.objs) == 0 {
   215  		return true
   216  	}
   217  
   218  	for i := range x.objs {
   219  		if x.objs[i].Equals(obj) {
   220  			return true
   221  		}
   222  	}
   223  
   224  	return false
   225  }
   226  
   227  // ObjectVerb enumerates object operations.
   228  type ObjectVerb int8
   229  
   230  const (
   231  	_ ObjectVerb = iota
   232  
   233  	VerbObjectPut       // Put rpc
   234  	VerbObjectGet       // Get rpc
   235  	VerbObjectHead      // Head rpc
   236  	VerbObjectSearch    // Search rpc
   237  	VerbObjectDelete    // Delete rpc
   238  	VerbObjectRange     // GetRange rpc
   239  	VerbObjectRangeHash // GetRangeHash rpc
   240  	VerbObjectPatch     // Patch rpc
   241  )
   242  
   243  // ForVerb specifies the object operation of the session scope. Each
   244  // Object is related to the single operation.
   245  //
   246  // See also AssertVerb.
   247  func (x *Object) ForVerb(verb ObjectVerb) {
   248  	x.verb = verb
   249  }
   250  
   251  // AssertVerb checks if Object relates to one of the given object operations.
   252  //
   253  // Zero Object relates to zero (unspecified) verb.
   254  //
   255  // See also ForVerb.
   256  func (x Object) AssertVerb(verbs ...ObjectVerb) bool {
   257  	for i := range verbs {
   258  		if verbs[i] == x.verb {
   259  			return true
   260  		}
   261  	}
   262  
   263  	return false
   264  }
   265  
   266  // ExpiredAt asserts "exp" claim.
   267  //
   268  // Zero Object is expired in any epoch.
   269  //
   270  // See also SetExp.
   271  func (x Object) ExpiredAt(epoch uint64) bool {
   272  	return x.expiredAt(epoch)
   273  }