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 }