2019-05-27 14:45:54 +03:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
2019-05-27 18:07:24 +03:00
|
|
|
"regexp"
|
2019-05-27 14:45:54 +03:00
|
|
|
"strings"
|
2019-05-27 18:07:24 +03:00
|
|
|
|
2019-05-30 12:28:56 -07:00
|
|
|
"github.com/golang/glog"
|
|
|
|
|
2019-05-27 18:07:24 +03:00
|
|
|
"github.com/minio/minio/pkg/wildcard"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Operator is string alias that represents selection operators enum
|
|
|
|
type Operator string
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Equal stands for ==
|
|
|
|
Equal Operator = ""
|
|
|
|
// MoreEqual stands for >=
|
|
|
|
MoreEqual Operator = ">="
|
|
|
|
// LessEqual stands for <=
|
|
|
|
LessEqual Operator = "<="
|
|
|
|
// NotEqual stands for !
|
|
|
|
NotEqual Operator = "!"
|
|
|
|
// More stands for >
|
|
|
|
More Operator = ">"
|
|
|
|
// Less stands for <
|
|
|
|
Less Operator = "<"
|
2019-05-27 14:45:54 +03:00
|
|
|
)
|
|
|
|
|
2019-06-20 18:21:55 +03:00
|
|
|
const relativePrefix Operator = "./"
|
|
|
|
const referenceSign Operator = "$()"
|
|
|
|
|
2019-05-27 14:45:54 +03:00
|
|
|
// ValidateValueWithPattern validates value with operators and wildcards
|
|
|
|
func ValidateValueWithPattern(value, pattern interface{}) bool {
|
|
|
|
switch typedPattern := pattern.(type) {
|
|
|
|
case bool:
|
|
|
|
typedValue, ok := value.(bool)
|
|
|
|
if !ok {
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected bool, found %T", value)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return typedPattern == typedValue
|
|
|
|
case int:
|
2019-05-27 18:07:24 +03:00
|
|
|
return validateValueWithIntPattern(value, int64(typedPattern))
|
|
|
|
case int64:
|
2019-05-27 14:45:54 +03:00
|
|
|
return validateValueWithIntPattern(value, typedPattern)
|
|
|
|
case float64:
|
|
|
|
return validateValueWithFloatPattern(value, typedPattern)
|
|
|
|
case string:
|
2019-05-27 18:07:24 +03:00
|
|
|
return validateValueWithStringPatterns(value, typedPattern)
|
|
|
|
case nil:
|
|
|
|
return validateValueWithNilPattern(value)
|
2019-05-27 14:45:54 +03:00
|
|
|
case map[string]interface{}, []interface{}:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warning("Maps and arrays as patterns are not supported")
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
default:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Unknown type as pattern: %T\n", pattern)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for int values during validation process
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateValueWithIntPattern(value interface{}, pattern int64) bool {
|
2019-05-27 14:45:54 +03:00
|
|
|
switch typedValue := value.(type) {
|
|
|
|
case int:
|
2019-05-27 18:07:24 +03:00
|
|
|
return int64(typedValue) == pattern
|
|
|
|
case int64:
|
2019-05-27 14:45:54 +03:00
|
|
|
return typedValue == pattern
|
|
|
|
case float64:
|
|
|
|
// check that float has no fraction
|
|
|
|
if typedValue == math.Trunc(typedValue) {
|
2019-05-27 18:07:24 +03:00
|
|
|
return int64(typedValue) == pattern
|
2019-05-27 14:45:54 +03:00
|
|
|
}
|
|
|
|
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected int, found float: %f\n", typedValue)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
default:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected int, found: %T\n", value)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for float values during validation process
|
2019-05-27 14:45:54 +03:00
|
|
|
func validateValueWithFloatPattern(value interface{}, pattern float64) bool {
|
|
|
|
switch typedValue := value.(type) {
|
|
|
|
case int:
|
|
|
|
// check that float has no fraction
|
|
|
|
if pattern == math.Trunc(pattern) {
|
|
|
|
return int(pattern) == value
|
|
|
|
}
|
|
|
|
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected float, found int: %d\n", typedValue)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
case float64:
|
|
|
|
return typedValue == pattern
|
|
|
|
default:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected float, found: %T\n", value)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for nil values during validation process
|
2019-05-27 14:45:54 +03:00
|
|
|
func validateValueWithNilPattern(value interface{}) bool {
|
|
|
|
switch typed := value.(type) {
|
|
|
|
case float64:
|
|
|
|
return typed == 0.0
|
|
|
|
case int:
|
|
|
|
return typed == 0
|
2019-05-27 18:07:24 +03:00
|
|
|
case int64:
|
|
|
|
return typed == 0
|
2019-05-27 14:45:54 +03:00
|
|
|
case string:
|
|
|
|
return typed == ""
|
|
|
|
case bool:
|
|
|
|
return typed == false
|
|
|
|
case nil:
|
|
|
|
return true
|
|
|
|
case map[string]interface{}, []interface{}:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Maps and arrays could not be checked with nil pattern")
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
default:
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Unknown type as value when checking for nil pattern: %T\n", value)
|
2019-05-27 14:45:54 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for pattern values during validation process
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateValueWithStringPatterns(value interface{}, pattern string) bool {
|
2019-05-27 14:45:54 +03:00
|
|
|
statements := strings.Split(pattern, "|")
|
2019-05-27 18:07:24 +03:00
|
|
|
for _, statement := range statements {
|
|
|
|
statement = strings.Trim(statement, " ")
|
|
|
|
if validateValueWithStringPattern(value, statement) {
|
2019-05-27 14:45:54 +03:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for single pattern value during validation process
|
|
|
|
// Detects if pattern has a number
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateValueWithStringPattern(value interface{}, pattern string) bool {
|
|
|
|
operator := getOperatorFromStringPattern(pattern)
|
|
|
|
pattern = pattern[len(operator):]
|
|
|
|
number, str := getNumberAndStringPartsFromPattern(pattern)
|
|
|
|
|
|
|
|
if "" == number {
|
|
|
|
return validateString(value, str, operator)
|
|
|
|
}
|
|
|
|
|
2019-05-28 14:07:15 +03:00
|
|
|
return validateNumberWithStr(value, number, str, operator)
|
2019-05-27 14:45:54 +03:00
|
|
|
}
|
2019-05-27 18:07:24 +03:00
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// Handler for string values
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateString(value interface{}, pattern string, operator Operator) bool {
|
|
|
|
if NotEqual == operator || Equal == operator {
|
|
|
|
strValue, ok := value.(string)
|
|
|
|
if !ok {
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Expected string, found %T\n", value)
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
wildcardResult := wildcard.Match(pattern, strValue)
|
|
|
|
|
|
|
|
if NotEqual == operator {
|
|
|
|
return !wildcardResult
|
|
|
|
}
|
|
|
|
|
|
|
|
return wildcardResult
|
|
|
|
}
|
|
|
|
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Operators >, >=, <, <= are not applicable to strings")
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// validateNumberWithStr applies wildcard to suffix and operator to numerical part
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateNumberWithStr(value interface{}, patternNumber, patternStr string, operator Operator) bool {
|
2019-06-05 13:43:07 +03:00
|
|
|
// pattern has suffix
|
2019-05-27 18:07:24 +03:00
|
|
|
if "" != patternStr {
|
|
|
|
typedValue, ok := value.(string)
|
|
|
|
if !ok {
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Number must have suffix: %s", patternStr)
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
valueNumber, valueStr := getNumberAndStringPartsFromPattern(typedValue)
|
|
|
|
if !wildcard.Match(patternStr, valueStr) {
|
2019-05-30 12:28:56 -07:00
|
|
|
glog.Warningf("Suffix %s has not passed wildcard check: %s", valueStr, patternStr)
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
return validateNumber(valueNumber, patternNumber, operator)
|
2019-05-27 18:07:24 +03:00
|
|
|
}
|
|
|
|
|
2019-05-28 14:25:29 +03:00
|
|
|
return validateNumber(value, patternNumber, operator)
|
2019-05-27 18:07:24 +03:00
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// validateNumber compares two numbers with operator
|
2019-05-27 18:07:24 +03:00
|
|
|
func validateNumber(value, pattern interface{}, operator Operator) bool {
|
2019-06-10 17:32:26 +03:00
|
|
|
floatPattern, err := convertToFloat(pattern)
|
|
|
|
if err != nil {
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
floatValue, err := convertToFloat(value)
|
|
|
|
if err != nil {
|
2019-05-27 18:07:24 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
switch operator {
|
|
|
|
case Equal:
|
|
|
|
return floatValue == floatPattern
|
|
|
|
case NotEqual:
|
|
|
|
return floatValue != floatPattern
|
|
|
|
case More:
|
|
|
|
return floatValue > floatPattern
|
|
|
|
case MoreEqual:
|
|
|
|
return floatValue >= floatPattern
|
|
|
|
case Less:
|
|
|
|
return floatValue < floatPattern
|
|
|
|
case LessEqual:
|
|
|
|
return floatValue <= floatPattern
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// getOperatorFromStringPattern parses opeartor from pattern
|
2019-05-27 18:07:24 +03:00
|
|
|
func getOperatorFromStringPattern(pattern string) Operator {
|
2019-05-28 13:13:57 +03:00
|
|
|
if len(pattern) < 2 {
|
|
|
|
return Equal
|
|
|
|
}
|
|
|
|
|
2019-05-27 18:07:24 +03:00
|
|
|
if pattern[:len(MoreEqual)] == string(MoreEqual) {
|
|
|
|
return MoreEqual
|
|
|
|
}
|
|
|
|
|
|
|
|
if pattern[:len(LessEqual)] == string(LessEqual) {
|
|
|
|
return LessEqual
|
|
|
|
}
|
|
|
|
|
|
|
|
if pattern[:len(More)] == string(More) {
|
|
|
|
return More
|
|
|
|
}
|
|
|
|
|
|
|
|
if pattern[:len(Less)] == string(Less) {
|
|
|
|
return Less
|
|
|
|
}
|
|
|
|
|
|
|
|
if pattern[:len(NotEqual)] == string(NotEqual) {
|
|
|
|
return NotEqual
|
|
|
|
}
|
|
|
|
|
2019-05-28 13:13:57 +03:00
|
|
|
return Equal
|
2019-05-27 18:07:24 +03:00
|
|
|
}
|
|
|
|
|
2019-06-10 17:32:26 +03:00
|
|
|
// detects numerical and string parts in pattern and returns them
|
2019-05-27 18:07:24 +03:00
|
|
|
func getNumberAndStringPartsFromPattern(pattern string) (number, str string) {
|
|
|
|
regexpStr := `^(\d*(\.\d+)?)(.*)`
|
|
|
|
re := regexp.MustCompile(regexpStr)
|
|
|
|
matches := re.FindAllStringSubmatch(pattern, -1)
|
|
|
|
match := matches[0]
|
|
|
|
return match[1], match[3]
|
|
|
|
}
|