storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/policy/condition/func.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package condition
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"sort"
    23  )
    24  
    25  // Function - condition function interface.
    26  type Function interface {
    27  	// evaluate() - evaluates this condition function with given values.
    28  	evaluate(values map[string][]string) bool
    29  
    30  	// key() - returns condition key used in this function.
    31  	key() Key
    32  
    33  	// name() - returns condition name of this function.
    34  	name() name
    35  
    36  	// String() - returns string representation of function.
    37  	String() string
    38  
    39  	// toMap - returns map representation of this function.
    40  	toMap() map[Key]ValueSet
    41  }
    42  
    43  // Functions - list of functions.
    44  type Functions []Function
    45  
    46  // Evaluate - evaluates all functions with given values map. Each function is evaluated
    47  // sequencely and next function is called only if current function succeeds.
    48  func (functions Functions) Evaluate(values map[string][]string) bool {
    49  	for _, f := range functions {
    50  		if !f.evaluate(values) {
    51  			return false
    52  		}
    53  	}
    54  
    55  	return true
    56  }
    57  
    58  // Keys - returns list of keys used in all functions.
    59  func (functions Functions) Keys() KeySet {
    60  	keySet := NewKeySet()
    61  
    62  	for _, f := range functions {
    63  		keySet.Add(f.key())
    64  	}
    65  
    66  	return keySet
    67  }
    68  
    69  // Clone clones Functions structure
    70  func (functions Functions) Clone() Functions {
    71  	funcs := []Function{}
    72  
    73  	for _, f := range functions {
    74  		vfn := conditionFuncMap[f.name()]
    75  		for key, values := range f.toMap() {
    76  			function, _ := vfn(key, values.Clone())
    77  			funcs = append(funcs, function)
    78  		}
    79  	}
    80  
    81  	return funcs
    82  }
    83  
    84  // Equals returns true if two Functions structures are equal
    85  func (functions Functions) Equals(funcs Functions) bool {
    86  	if len(functions) != len(funcs) {
    87  		return false
    88  	}
    89  	for _, fi := range functions {
    90  		fistr := fi.String()
    91  		found := false
    92  		for _, fj := range funcs {
    93  			if fistr == fj.String() {
    94  				found = true
    95  				break
    96  			}
    97  		}
    98  		if !found {
    99  			return false
   100  		}
   101  	}
   102  	return true
   103  }
   104  
   105  // MarshalJSON - encodes Functions to  JSON data.
   106  func (functions Functions) MarshalJSON() ([]byte, error) {
   107  	nm := make(map[name]map[Key]ValueSet)
   108  
   109  	for _, f := range functions {
   110  		if _, ok := nm[f.name()]; ok {
   111  			for k, v := range f.toMap() {
   112  				nm[f.name()][k] = v
   113  			}
   114  		} else {
   115  			nm[f.name()] = f.toMap()
   116  		}
   117  	}
   118  
   119  	return json.Marshal(nm)
   120  }
   121  
   122  func (functions Functions) String() string {
   123  	funcStrings := []string{}
   124  	for _, f := range functions {
   125  		s := fmt.Sprintf("%v", f)
   126  		funcStrings = append(funcStrings, s)
   127  	}
   128  	sort.Strings(funcStrings)
   129  
   130  	return fmt.Sprintf("%v", funcStrings)
   131  }
   132  
   133  var conditionFuncMap = map[name]func(Key, ValueSet) (Function, error){
   134  	stringEquals:              newStringEqualsFunc,
   135  	stringNotEquals:           newStringNotEqualsFunc,
   136  	stringEqualsIgnoreCase:    newStringEqualsIgnoreCaseFunc,
   137  	stringNotEqualsIgnoreCase: newStringNotEqualsIgnoreCaseFunc,
   138  	binaryEquals:              newBinaryEqualsFunc,
   139  	stringLike:                newStringLikeFunc,
   140  	stringNotLike:             newStringNotLikeFunc,
   141  	ipAddress:                 newIPAddressFunc,
   142  	notIPAddress:              newNotIPAddressFunc,
   143  	null:                      newNullFunc,
   144  	boolean:                   newBooleanFunc,
   145  	numericEquals:             newNumericEqualsFunc,
   146  	numericNotEquals:          newNumericNotEqualsFunc,
   147  	numericLessThan:           newNumericLessThanFunc,
   148  	numericLessThanEquals:     newNumericLessThanEqualsFunc,
   149  	numericGreaterThan:        newNumericGreaterThanFunc,
   150  	numericGreaterThanEquals:  newNumericGreaterThanEqualsFunc,
   151  	dateEquals:                newDateEqualsFunc,
   152  	dateNotEquals:             newDateNotEqualsFunc,
   153  	dateLessThan:              newDateLessThanFunc,
   154  	dateLessThanEquals:        newDateLessThanEqualsFunc,
   155  	dateGreaterThan:           newDateGreaterThanFunc,
   156  	dateGreaterThanEquals:     newDateGreaterThanEqualsFunc,
   157  	// Add new conditions here.
   158  }
   159  
   160  // UnmarshalJSON - decodes JSON data to Functions.
   161  func (functions *Functions) UnmarshalJSON(data []byte) error {
   162  	// As string kind, int kind then json.Unmarshaler is checked at
   163  	// https://github.com/golang/go/blob/master/src/encoding/json/decode.go#L618
   164  	// UnmarshalJSON() is not called for types extending string
   165  	// see https://play.golang.org/p/HrSsKksHvrS, better way to do is
   166  	// https://play.golang.org/p/y9ElWpBgVAB
   167  	//
   168  	// Due to this issue, name and Key types cannot be used as map keys below.
   169  	nm := make(map[string]map[string]ValueSet)
   170  	if err := json.Unmarshal(data, &nm); err != nil {
   171  		return err
   172  	}
   173  
   174  	if len(nm) == 0 {
   175  		return fmt.Errorf("condition must not be empty")
   176  	}
   177  
   178  	funcs := []Function{}
   179  	for nameString, args := range nm {
   180  		n, err := parseName(nameString)
   181  		if err != nil {
   182  			return err
   183  		}
   184  
   185  		for keyString, values := range args {
   186  			key, err := parseKey(keyString)
   187  			if err != nil {
   188  				return err
   189  			}
   190  
   191  			vfn, ok := conditionFuncMap[n]
   192  			if !ok {
   193  				return fmt.Errorf("condition %v is not handled", n)
   194  			}
   195  
   196  			f, err := vfn(key, values)
   197  			if err != nil {
   198  				return err
   199  			}
   200  
   201  			funcs = append(funcs, f)
   202  		}
   203  	}
   204  
   205  	*functions = funcs
   206  
   207  	return nil
   208  }
   209  
   210  // GobEncode - encodes Functions to gob data.
   211  func (functions Functions) GobEncode() ([]byte, error) {
   212  	return functions.MarshalJSON()
   213  }
   214  
   215  // GobDecode - decodes gob data to Functions.
   216  func (functions *Functions) GobDecode(data []byte) error {
   217  	return functions.UnmarshalJSON(data)
   218  }
   219  
   220  // NewFunctions - returns new Functions with given function list.
   221  func NewFunctions(functions ...Function) Functions {
   222  	return Functions(functions)
   223  }