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

     1  package eacl
     2  
     3  import (
     4  	"strconv"
     5  
     6  	v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
     7  )
     8  
     9  // Filter defines check conditions if request header is matched or not. Matched
    10  // header means that request should be processed according to ContainerEACL action.
    11  //
    12  // Filter is compatible with v2 acl.EACLRecord.Filter message.
    13  type Filter struct {
    14  	from    FilterHeaderType
    15  	matcher Match
    16  	key     filterKey
    17  	value   stringEncoder
    18  }
    19  
    20  type staticStringer string
    21  
    22  type u64Stringer uint64
    23  
    24  type filterKey struct {
    25  	typ filterKeyType
    26  
    27  	str string
    28  }
    29  
    30  // enumeration of reserved filter keys.
    31  type filterKeyType int
    32  
    33  const (
    34  	_ filterKeyType = iota
    35  	fKeyObjVersion
    36  	fKeyObjID
    37  	fKeyObjContainerID
    38  	fKeyObjOwnerID
    39  	fKeyObjCreationEpoch
    40  	fKeyObjPayloadLength
    41  	fKeyObjPayloadHash
    42  	fKeyObjType
    43  	fKeyObjHomomorphicHash
    44  	fKeyObjLast // helper, used in tests
    45  )
    46  
    47  func (s staticStringer) EncodeToString() string {
    48  	return string(s)
    49  }
    50  
    51  func (u u64Stringer) EncodeToString() string {
    52  	return strconv.FormatUint(uint64(u), 10)
    53  }
    54  
    55  // Value returns filtered string value.
    56  func (f Filter) Value() string {
    57  	return f.value.EncodeToString()
    58  }
    59  
    60  // Matcher returns filter Match type.
    61  func (f Filter) Matcher() Match {
    62  	return f.matcher
    63  }
    64  
    65  // Key returns key to the filtered header.
    66  func (f Filter) Key() string {
    67  	return f.key.String()
    68  }
    69  
    70  // From returns FilterHeaderType that defined which header will be filtered.
    71  func (f Filter) From() FilterHeaderType {
    72  	return f.from
    73  }
    74  
    75  // ToV2 converts Filter to v2 acl.EACLRecord.Filter message.
    76  //
    77  // Nil Filter converts to nil.
    78  func (f *Filter) ToV2() *v2acl.HeaderFilter {
    79  	if f == nil {
    80  		return nil
    81  	}
    82  
    83  	filter := new(v2acl.HeaderFilter)
    84  	filter.SetValue(f.value.EncodeToString())
    85  	filter.SetKey(f.key.String())
    86  	filter.SetMatchType(f.matcher.ToV2())
    87  	filter.SetHeaderType(f.from.ToV2())
    88  
    89  	return filter
    90  }
    91  
    92  func (k filterKey) String() string {
    93  	switch k.typ {
    94  	default:
    95  		return k.str
    96  	case fKeyObjVersion:
    97  		return v2acl.FilterObjectVersion
    98  	case fKeyObjID:
    99  		return v2acl.FilterObjectID
   100  	case fKeyObjContainerID:
   101  		return v2acl.FilterObjectContainerID
   102  	case fKeyObjOwnerID:
   103  		return v2acl.FilterObjectOwnerID
   104  	case fKeyObjCreationEpoch:
   105  		return v2acl.FilterObjectCreationEpoch
   106  	case fKeyObjPayloadLength:
   107  		return v2acl.FilterObjectPayloadLength
   108  	case fKeyObjPayloadHash:
   109  		return v2acl.FilterObjectPayloadHash
   110  	case fKeyObjType:
   111  		return v2acl.FilterObjectType
   112  	case fKeyObjHomomorphicHash:
   113  		return v2acl.FilterObjectHomomorphicHash
   114  	}
   115  }
   116  
   117  func (k *filterKey) fromString(s string) {
   118  	switch s {
   119  	default:
   120  		k.typ, k.str = 0, s
   121  	case v2acl.FilterObjectVersion:
   122  		k.typ, k.str = fKeyObjVersion, ""
   123  	case v2acl.FilterObjectID:
   124  		k.typ, k.str = fKeyObjID, ""
   125  	case v2acl.FilterObjectContainerID:
   126  		k.typ, k.str = fKeyObjContainerID, ""
   127  	case v2acl.FilterObjectOwnerID:
   128  		k.typ, k.str = fKeyObjOwnerID, ""
   129  	case v2acl.FilterObjectCreationEpoch:
   130  		k.typ, k.str = fKeyObjCreationEpoch, ""
   131  	case v2acl.FilterObjectPayloadLength:
   132  		k.typ, k.str = fKeyObjPayloadLength, ""
   133  	case v2acl.FilterObjectPayloadHash:
   134  		k.typ, k.str = fKeyObjPayloadHash, ""
   135  	case v2acl.FilterObjectType:
   136  		k.typ, k.str = fKeyObjType, ""
   137  	case v2acl.FilterObjectHomomorphicHash:
   138  		k.typ, k.str = fKeyObjHomomorphicHash, ""
   139  	}
   140  }
   141  
   142  // NewFilter creates, initializes and returns blank Filter instance.
   143  //
   144  // Defaults:
   145  //   - header type: HeaderTypeUnknown;
   146  //   - matcher: MatchUnknown;
   147  //   - key: "";
   148  //   - value: "".
   149  func NewFilter() *Filter {
   150  	return NewFilterFromV2(new(v2acl.HeaderFilter))
   151  }
   152  
   153  // NewFilterFromV2 converts v2 acl.EACLRecord.Filter message to Filter.
   154  func NewFilterFromV2(filter *v2acl.HeaderFilter) *Filter {
   155  	f := new(Filter)
   156  
   157  	if filter == nil {
   158  		return f
   159  	}
   160  
   161  	f.from = FilterHeaderTypeFromV2(filter.GetHeaderType())
   162  	f.matcher = MatchFromV2(filter.GetMatchType())
   163  	f.key.fromString(filter.GetKey())
   164  	f.value = staticStringer(filter.GetValue())
   165  
   166  	return f
   167  }
   168  
   169  // Marshal marshals Filter into a protobuf binary form.
   170  func (f *Filter) Marshal() ([]byte, error) {
   171  	return f.ToV2().StableMarshal(nil), nil
   172  }
   173  
   174  // Unmarshal unmarshals protobuf binary representation of Filter.
   175  func (f *Filter) Unmarshal(data []byte) error {
   176  	fV2 := new(v2acl.HeaderFilter)
   177  	if err := fV2.Unmarshal(data); err != nil {
   178  		return err
   179  	}
   180  
   181  	*f = *NewFilterFromV2(fV2)
   182  
   183  	return nil
   184  }
   185  
   186  // MarshalJSON encodes Filter to protobuf JSON format.
   187  func (f *Filter) MarshalJSON() ([]byte, error) {
   188  	return f.ToV2().MarshalJSON()
   189  }
   190  
   191  // UnmarshalJSON decodes Filter from protobuf JSON format.
   192  func (f *Filter) UnmarshalJSON(data []byte) error {
   193  	fV2 := new(v2acl.HeaderFilter)
   194  	if err := fV2.UnmarshalJSON(data); err != nil {
   195  		return err
   196  	}
   197  
   198  	*f = *NewFilterFromV2(fV2)
   199  
   200  	return nil
   201  }
   202  
   203  // equalFilters compares Filter with each other.
   204  func equalFilters(f1, f2 Filter) bool {
   205  	return f1.From() == f2.From() &&
   206  		f1.Matcher() == f2.Matcher() &&
   207  		f1.Key() == f2.Key() &&
   208  		f1.Value() == f2.Value()
   209  }