1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
package bexpr
import (
"fmt"
"regexp"
)
func validateRecurse(ast Expression, fields FieldConfigurations, maxRawValueLength int) (int, error) {
switch node := ast.(type) {
case *UnaryExpression:
switch node.Operator {
case UnaryOpNot:
// this is fine
default:
return 0, fmt.Errorf("Invalid unary expression operator: %d", node.Operator)
}
if node.Operand == nil {
return 0, fmt.Errorf("Invalid unary expression operand: nil")
}
return validateRecurse(node.Operand, fields, maxRawValueLength)
case *BinaryExpression:
switch node.Operator {
case BinaryOpAnd, BinaryOpOr:
// this is fine
default:
return 0, fmt.Errorf("Invalid binary expression operator: %d", node.Operator)
}
if node.Left == nil {
return 0, fmt.Errorf("Invalid left hand side of binary expression: nil")
} else if node.Right == nil {
return 0, fmt.Errorf("Invalid right hand side of binary expression: nil")
}
leftMatches, err := validateRecurse(node.Left, fields, maxRawValueLength)
if err != nil {
return leftMatches, err
}
rightMatches, err := validateRecurse(node.Right, fields, maxRawValueLength)
return leftMatches + rightMatches, err
case *MatchExpression:
if len(node.Selector) < 1 {
return 1, fmt.Errorf("Invalid selector: %q", node.Selector)
}
if node.Value != nil && maxRawValueLength != 0 && len(node.Value.Raw) > maxRawValueLength {
return 1, fmt.Errorf("Value in expression with length %d for selector %q exceeds maximum length of", len(node.Value.Raw), maxRawValueLength)
}
// exit early if we have no fields to check against
if len(fields) < 1 {
return 1, nil
}
configs := fields
var lastConfig *FieldConfiguration
// validate the selector
for idx, field := range node.Selector {
if fcfg, ok := configs[FieldName(field)]; ok {
lastConfig = fcfg
configs = fcfg.SubFields
} else if fcfg, ok := configs[FieldNameAny]; ok {
lastConfig = fcfg
configs = fcfg.SubFields
} else {
return 1, fmt.Errorf("Selector %q is not valid", node.Selector[:idx+1])
}
// this just verifies that the FieldConfigurations we are using was created properly
if lastConfig == nil {
return 1, fmt.Errorf("FieldConfiguration for selector %q is nil", node.Selector[:idx])
}
}
// check the operator
found := false
for _, op := range lastConfig.SupportedOperations {
if op == node.Operator {
found = true
break
}
}
if !found {
return 1, fmt.Errorf("Invalid match operator %q for selector %q", node.Operator, node.Selector)
}
// coerce/validate the value
if node.Value != nil {
if lastConfig.CoerceFn != nil {
coerced, err := lastConfig.CoerceFn(node.Value.Raw)
if err != nil {
return 1, fmt.Errorf("Failed to coerce value %q for selector %q: %v", node.Value.Raw, node.Selector, err)
}
node.Value.Converted = coerced
}
if node.Operator == MatchMatches || node.Operator == MatchNotMatches {
var regRaw string
if strVal, ok := node.Value.Converted.(string); ok {
regRaw = strVal
} else if node.Value.Converted == nil {
regRaw = node.Value.Raw
} else {
return 1, fmt.Errorf("Match operator %q cannot be used with fields whose coercion functions return non string values", node.Operator)
}
re, err := regexp.Compile(regRaw)
if err != nil {
return 1, fmt.Errorf("Failed to compile regular expression %q: %v", regRaw, err)
}
node.Value.Converted = re
}
} else {
switch node.Operator {
case MatchIsEmpty, MatchIsNotEmpty:
// these don't require values
default:
return 1, fmt.Errorf("Match operator %q requires a non-nil value", node.Operator)
}
}
return 1, nil
}
return 0, fmt.Errorf("Cannot validate: Invalid AST")
}
func validate(ast Expression, fields FieldConfigurations, maxMatches, maxRawValueLength int) error {
matches, err := validateRecurse(ast, fields, maxRawValueLength)
if err != nil {
return err
}
if maxMatches != 0 && matches > maxMatches {
return fmt.Errorf("Number of match expressions (%d) exceeds the limit (%d)", matches, maxMatches)
}
return nil
}
|