mirror of https://github.com/minio/minio.git
225 lines
6.0 KiB
Go
225 lines
6.0 KiB
Go
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
//
|
|
// This file is part of MinIO Object Storage stack
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package condition
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// Function - condition function interface.
|
|
type Function interface {
|
|
// evaluate() - evaluates this condition function with given values.
|
|
evaluate(values map[string][]string) bool
|
|
|
|
// key() - returns condition key used in this function.
|
|
key() Key
|
|
|
|
// name() - returns condition name of this function.
|
|
name() name
|
|
|
|
// String() - returns string representation of function.
|
|
String() string
|
|
|
|
// toMap - returns map representation of this function.
|
|
toMap() map[Key]ValueSet
|
|
}
|
|
|
|
// Functions - list of functions.
|
|
type Functions []Function
|
|
|
|
// Evaluate - evaluates all functions with given values map. Each function is evaluated
|
|
// sequencely and next function is called only if current function succeeds.
|
|
func (functions Functions) Evaluate(values map[string][]string) bool {
|
|
for _, f := range functions {
|
|
if !f.evaluate(values) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Keys - returns list of keys used in all functions.
|
|
func (functions Functions) Keys() KeySet {
|
|
keySet := NewKeySet()
|
|
|
|
for _, f := range functions {
|
|
keySet.Add(f.key())
|
|
}
|
|
|
|
return keySet
|
|
}
|
|
|
|
// Clone clones Functions structure
|
|
func (functions Functions) Clone() Functions {
|
|
funcs := []Function{}
|
|
|
|
for _, f := range functions {
|
|
vfn := conditionFuncMap[f.name()]
|
|
for key, values := range f.toMap() {
|
|
function, _ := vfn(key, values.Clone())
|
|
funcs = append(funcs, function)
|
|
}
|
|
}
|
|
|
|
return funcs
|
|
}
|
|
|
|
// Equals returns true if two Functions structures are equal
|
|
func (functions Functions) Equals(funcs Functions) bool {
|
|
if len(functions) != len(funcs) {
|
|
return false
|
|
}
|
|
for _, fi := range functions {
|
|
fistr := fi.String()
|
|
found := false
|
|
for _, fj := range funcs {
|
|
if fistr == fj.String() {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// MarshalJSON - encodes Functions to JSON data.
|
|
func (functions Functions) MarshalJSON() ([]byte, error) {
|
|
nm := make(map[name]map[Key]ValueSet)
|
|
|
|
for _, f := range functions {
|
|
if _, ok := nm[f.name()]; ok {
|
|
for k, v := range f.toMap() {
|
|
nm[f.name()][k] = v
|
|
}
|
|
} else {
|
|
nm[f.name()] = f.toMap()
|
|
}
|
|
}
|
|
|
|
return json.Marshal(nm)
|
|
}
|
|
|
|
func (functions Functions) String() string {
|
|
funcStrings := []string{}
|
|
for _, f := range functions {
|
|
s := fmt.Sprintf("%v", f)
|
|
funcStrings = append(funcStrings, s)
|
|
}
|
|
sort.Strings(funcStrings)
|
|
|
|
return fmt.Sprintf("%v", funcStrings)
|
|
}
|
|
|
|
var conditionFuncMap = map[name]func(Key, ValueSet) (Function, error){
|
|
stringEquals: newStringEqualsFunc,
|
|
stringNotEquals: newStringNotEqualsFunc,
|
|
stringEqualsIgnoreCase: newStringEqualsIgnoreCaseFunc,
|
|
stringNotEqualsIgnoreCase: newStringNotEqualsIgnoreCaseFunc,
|
|
binaryEquals: newBinaryEqualsFunc,
|
|
stringLike: newStringLikeFunc,
|
|
stringNotLike: newStringNotLikeFunc,
|
|
ipAddress: newIPAddressFunc,
|
|
notIPAddress: newNotIPAddressFunc,
|
|
null: newNullFunc,
|
|
boolean: newBooleanFunc,
|
|
numericEquals: newNumericEqualsFunc,
|
|
numericNotEquals: newNumericNotEqualsFunc,
|
|
numericLessThan: newNumericLessThanFunc,
|
|
numericLessThanEquals: newNumericLessThanEqualsFunc,
|
|
numericGreaterThan: newNumericGreaterThanFunc,
|
|
numericGreaterThanEquals: newNumericGreaterThanEqualsFunc,
|
|
dateEquals: newDateEqualsFunc,
|
|
dateNotEquals: newDateNotEqualsFunc,
|
|
dateLessThan: newDateLessThanFunc,
|
|
dateLessThanEquals: newDateLessThanEqualsFunc,
|
|
dateGreaterThan: newDateGreaterThanFunc,
|
|
dateGreaterThanEquals: newDateGreaterThanEqualsFunc,
|
|
// Add new conditions here.
|
|
}
|
|
|
|
// UnmarshalJSON - decodes JSON data to Functions.
|
|
func (functions *Functions) UnmarshalJSON(data []byte) error {
|
|
// As string kind, int kind then json.Unmarshaler is checked at
|
|
// https://github.com/golang/go/blob/master/src/encoding/json/decode.go#L618
|
|
// UnmarshalJSON() is not called for types extending string
|
|
// see https://play.golang.org/p/HrSsKksHvrS, better way to do is
|
|
// https://play.golang.org/p/y9ElWpBgVAB
|
|
//
|
|
// Due to this issue, name and Key types cannot be used as map keys below.
|
|
nm := make(map[string]map[string]ValueSet)
|
|
if err := json.Unmarshal(data, &nm); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(nm) == 0 {
|
|
return fmt.Errorf("condition must not be empty")
|
|
}
|
|
|
|
funcs := []Function{}
|
|
for nameString, args := range nm {
|
|
n, err := parseName(nameString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for keyString, values := range args {
|
|
key, err := parseKey(keyString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vfn, ok := conditionFuncMap[n]
|
|
if !ok {
|
|
return fmt.Errorf("condition %v is not handled", n)
|
|
}
|
|
|
|
f, err := vfn(key, values)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
funcs = append(funcs, f)
|
|
}
|
|
}
|
|
|
|
*functions = funcs
|
|
|
|
return nil
|
|
}
|
|
|
|
// GobEncode - encodes Functions to gob data.
|
|
func (functions Functions) GobEncode() ([]byte, error) {
|
|
return functions.MarshalJSON()
|
|
}
|
|
|
|
// GobDecode - decodes gob data to Functions.
|
|
func (functions *Functions) GobDecode(data []byte) error {
|
|
return functions.UnmarshalJSON(data)
|
|
}
|
|
|
|
// NewFunctions - returns new Functions with given function list.
|
|
func NewFunctions(functions ...Function) Functions {
|
|
return Functions(functions)
|
|
}
|