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

     1  package eacl
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  
     6  	v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
     7  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
     8  	cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
     9  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
    10  	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
    11  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
    12  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
    13  )
    14  
    15  // Record of the ContainerEACL rule, that defines ContainerEACL action, targets for this action,
    16  // object service operation and filters for request headers.
    17  //
    18  // Record is compatible with v2 acl.EACLRecord message.
    19  type Record struct {
    20  	action    Action
    21  	operation Operation
    22  	filters   []Filter
    23  	targets   []Target
    24  }
    25  
    26  // Targets returns list of target subjects to apply ACL rule to.
    27  func (r Record) Targets() []Target {
    28  	return r.targets
    29  }
    30  
    31  // SetTargets sets list of target subjects to apply ACL rule to.
    32  func (r *Record) SetTargets(targets ...Target) {
    33  	r.targets = targets
    34  }
    35  
    36  // Filters returns list of filters to match and see if rule is applicable.
    37  func (r Record) Filters() []Filter {
    38  	return r.filters
    39  }
    40  
    41  // Operation returns FrostFS request verb to match.
    42  func (r Record) Operation() Operation {
    43  	return r.operation
    44  }
    45  
    46  // SetOperation sets FrostFS request verb to match.
    47  func (r *Record) SetOperation(operation Operation) {
    48  	r.operation = operation
    49  }
    50  
    51  // Action returns rule execution result.
    52  func (r Record) Action() Action {
    53  	return r.action
    54  }
    55  
    56  // SetAction sets rule execution result.
    57  func (r *Record) SetAction(action Action) {
    58  	r.action = action
    59  }
    60  
    61  // AddRecordTarget adds single Target to the Record.
    62  func AddRecordTarget(r *Record, t *Target) {
    63  	r.SetTargets(append(r.Targets(), *t)...)
    64  }
    65  
    66  // AddFormedTarget forms Target with specified Role and list of
    67  // ECDSA public keys and adds it to the Record.
    68  func AddFormedTarget(r *Record, role Role, keys ...ecdsa.PublicKey) {
    69  	t := NewTarget()
    70  	t.SetRole(role)
    71  
    72  	SetTargetECDSAKeys(t, ecdsaKeysToPtrs(keys)...)
    73  	AddRecordTarget(r, t)
    74  }
    75  
    76  type stringEncoder interface {
    77  	EncodeToString() string
    78  }
    79  
    80  func (r *Record) addFilter(from FilterHeaderType, m Match, keyTyp filterKeyType, key string, val stringEncoder) {
    81  	filter := Filter{
    82  		from: from,
    83  		key: filterKey{
    84  			typ: keyTyp,
    85  			str: key,
    86  		},
    87  		matcher: m,
    88  		value:   val,
    89  	}
    90  
    91  	r.filters = append(r.filters, filter)
    92  }
    93  
    94  func (r *Record) addObjectFilter(m Match, keyTyp filterKeyType, key string, val stringEncoder) {
    95  	r.addFilter(HeaderFromObject, m, keyTyp, key, val)
    96  }
    97  
    98  func (r *Record) addObjectReservedFilter(m Match, typ filterKeyType, val stringEncoder) {
    99  	r.addObjectFilter(m, typ, "", val)
   100  }
   101  
   102  // AddFilter adds generic filter.
   103  func (r *Record) AddFilter(from FilterHeaderType, matcher Match, name, value string) {
   104  	r.addFilter(from, matcher, 0, name, staticStringer(value))
   105  }
   106  
   107  // AddObjectAttributeFilter adds filter by object attribute.
   108  func (r *Record) AddObjectAttributeFilter(m Match, key, value string) {
   109  	r.addObjectFilter(m, 0, key, staticStringer(value))
   110  }
   111  
   112  // AddObjectVersionFilter adds filter by object version.
   113  func (r *Record) AddObjectVersionFilter(m Match, v *version.Version) {
   114  	r.addObjectReservedFilter(m, fKeyObjVersion, staticStringer(version.EncodeToString(*v)))
   115  }
   116  
   117  // AddObjectIDFilter adds filter by object ID.
   118  func (r *Record) AddObjectIDFilter(m Match, id oid.ID) {
   119  	r.addObjectReservedFilter(m, fKeyObjID, id)
   120  }
   121  
   122  // AddObjectContainerIDFilter adds filter by object container ID.
   123  func (r *Record) AddObjectContainerIDFilter(m Match, id cid.ID) {
   124  	r.addObjectReservedFilter(m, fKeyObjContainerID, id)
   125  }
   126  
   127  // AddObjectOwnerIDFilter adds filter by object owner ID.
   128  func (r *Record) AddObjectOwnerIDFilter(m Match, id user.ID) {
   129  	r.addObjectReservedFilter(m, fKeyObjOwnerID, id)
   130  }
   131  
   132  // AddObjectCreationEpoch adds filter by object creation epoch.
   133  func (r *Record) AddObjectCreationEpoch(m Match, epoch uint64) {
   134  	r.addObjectReservedFilter(m, fKeyObjCreationEpoch, u64Stringer(epoch))
   135  }
   136  
   137  // AddObjectPayloadLengthFilter adds filter by object payload length.
   138  func (r *Record) AddObjectPayloadLengthFilter(m Match, size uint64) {
   139  	r.addObjectReservedFilter(m, fKeyObjPayloadLength, u64Stringer(size))
   140  }
   141  
   142  // AddObjectPayloadHashFilter adds filter by object payload hash value.
   143  func (r *Record) AddObjectPayloadHashFilter(m Match, h checksum.Checksum) {
   144  	r.addObjectReservedFilter(m, fKeyObjPayloadHash, staticStringer(h.String()))
   145  }
   146  
   147  // AddObjectTypeFilter adds filter by object type.
   148  func (r *Record) AddObjectTypeFilter(m Match, t object.Type) {
   149  	r.addObjectReservedFilter(m, fKeyObjType, staticStringer(t.String()))
   150  }
   151  
   152  // AddObjectHomomorphicHashFilter adds filter by object payload homomorphic hash value.
   153  func (r *Record) AddObjectHomomorphicHashFilter(m Match, h checksum.Checksum) {
   154  	r.addObjectReservedFilter(m, fKeyObjHomomorphicHash, staticStringer(h.String()))
   155  }
   156  
   157  // ToV2 converts Record to v2 acl.EACLRecord message.
   158  //
   159  // Nil Record converts to nil.
   160  func (r *Record) ToV2() *v2acl.Record {
   161  	if r == nil {
   162  		return nil
   163  	}
   164  
   165  	v2 := new(v2acl.Record)
   166  
   167  	if r.targets != nil {
   168  		targets := make([]v2acl.Target, len(r.targets))
   169  		for i := range r.targets {
   170  			targets[i] = *r.targets[i].ToV2()
   171  		}
   172  
   173  		v2.SetTargets(targets)
   174  	}
   175  
   176  	if r.filters != nil {
   177  		filters := make([]v2acl.HeaderFilter, len(r.filters))
   178  		for i := range r.filters {
   179  			filters[i] = *r.filters[i].ToV2()
   180  		}
   181  
   182  		v2.SetFilters(filters)
   183  	}
   184  
   185  	v2.SetAction(r.action.ToV2())
   186  	v2.SetOperation(r.operation.ToV2())
   187  
   188  	return v2
   189  }
   190  
   191  // NewRecord creates and returns blank Record instance.
   192  //
   193  // Defaults:
   194  //   - action: ActionUnknown;
   195  //   - operation: OperationUnknown;
   196  //   - targets: nil,
   197  //   - filters: nil.
   198  func NewRecord() *Record {
   199  	return new(Record)
   200  }
   201  
   202  // CreateRecord creates, initializes with parameters and returns Record instance.
   203  func CreateRecord(action Action, operation Operation) *Record {
   204  	r := NewRecord()
   205  	r.action = action
   206  	r.operation = operation
   207  	r.targets = []Target{}
   208  	r.filters = []Filter{}
   209  
   210  	return r
   211  }
   212  
   213  // NewRecordFromV2 converts v2 acl.EACLRecord message to Record.
   214  func NewRecordFromV2(record *v2acl.Record) *Record {
   215  	r := NewRecord()
   216  
   217  	if record == nil {
   218  		return r
   219  	}
   220  
   221  	r.action = ActionFromV2(record.GetAction())
   222  	r.operation = OperationFromV2(record.GetOperation())
   223  
   224  	v2targets := record.GetTargets()
   225  	v2filters := record.GetFilters()
   226  
   227  	r.targets = make([]Target, len(v2targets))
   228  	for i := range v2targets {
   229  		r.targets[i] = *NewTargetFromV2(&v2targets[i])
   230  	}
   231  
   232  	r.filters = make([]Filter, len(v2filters))
   233  	for i := range v2filters {
   234  		r.filters[i] = *NewFilterFromV2(&v2filters[i])
   235  	}
   236  
   237  	return r
   238  }
   239  
   240  // Marshal marshals Record into a protobuf binary form.
   241  func (r *Record) Marshal() ([]byte, error) {
   242  	return r.ToV2().StableMarshal(nil), nil
   243  }
   244  
   245  // Unmarshal unmarshals protobuf binary representation of Record.
   246  func (r *Record) Unmarshal(data []byte) error {
   247  	fV2 := new(v2acl.Record)
   248  	if err := fV2.Unmarshal(data); err != nil {
   249  		return err
   250  	}
   251  
   252  	*r = *NewRecordFromV2(fV2)
   253  
   254  	return nil
   255  }
   256  
   257  // MarshalJSON encodes Record to protobuf JSON format.
   258  func (r *Record) MarshalJSON() ([]byte, error) {
   259  	return r.ToV2().MarshalJSON()
   260  }
   261  
   262  // UnmarshalJSON decodes Record from protobuf JSON format.
   263  func (r *Record) UnmarshalJSON(data []byte) error {
   264  	tV2 := new(v2acl.Record)
   265  	if err := tV2.UnmarshalJSON(data); err != nil {
   266  		return err
   267  	}
   268  
   269  	*r = *NewRecordFromV2(tV2)
   270  
   271  	return nil
   272  }
   273  
   274  // equalRecords compares Record with each other.
   275  func equalRecords(r1, r2 Record) bool {
   276  	if r1.Operation() != r2.Operation() ||
   277  		r1.Action() != r2.Action() {
   278  		return false
   279  	}
   280  
   281  	fs1, fs2 := r1.Filters(), r2.Filters()
   282  	ts1, ts2 := r1.Targets(), r2.Targets()
   283  
   284  	if len(fs1) != len(fs2) ||
   285  		len(ts1) != len(ts2) {
   286  		return false
   287  	}
   288  
   289  	for i := range len(fs1) {
   290  		if !equalFilters(fs1[i], fs2[i]) {
   291  			return false
   292  		}
   293  	}
   294  
   295  	for i := range len(ts1) {
   296  		if !equalTargets(ts1[i], ts2[i]) {
   297  			return false
   298  		}
   299  	}
   300  
   301  	return true
   302  }