Merge pull request #92 from cloudflare/filters-validation

More strict filter validation
This commit is contained in:
Łukasz Mierzwa
2017-05-06 16:51:38 +01:00
committed by GitHub
3 changed files with 77 additions and 40 deletions

View File

@@ -57,43 +57,49 @@ func NewFilter(expression string) FilterT {
invalid := alwaysInvalidFilter{}
invalid.init("", nil, expression, false, expression)
reExp := fmt.Sprintf("^(?P<matched>(%s))(?P<operator>(%s))(?P<value>(.*))", filterRegex, matcherRegex)
re := regexp.MustCompile(reExp)
match := re.FindStringSubmatch(expression)
result := make(map[string]string)
for i, name := range re.SubexpNames() {
if name != "" && i > 0 && i <= len(match) {
result[name] = match[i]
}
}
matched, _ := result["matched"]
operator, _ := result["operator"]
value, _ := result["value"]
if matched == "" && operator == "" && value == "" {
// no "filter=" part, just the value, use fuzzy filter
f := newFuzzyFilter()
matcher, err := newMatcher(regexpOperator)
if err != nil {
f.init("", nil, expression, false, expression)
} else {
f.init("", &matcher, expression, true, expression)
}
return f
}
if value == "" {
// there's no value, so it's always invalid
return &invalid
}
if operator == "" {
// no operator, no valid filter here
return &invalid
}
// we have "filter=" part, lookup filter that matches
for _, fc := range AllFilters {
f := fc.Factory()
reExp := fmt.Sprintf("^(?P<matched>(%s))(?P<operator>(%s))(?P<value>(.*))", fc.Label, matcherRegex)
re := regexp.MustCompile(reExp)
match := re.FindStringSubmatch(expression)
result := make(map[string]string)
for i, name := range re.SubexpNames() {
if name != "" && i > 0 && i <= len(match) {
result[name] = match[i]
}
}
matched, found := result["matched"]
if !found && fc.IsSimple {
matcher, err := newMatcher(regexpOperator)
if err != nil {
f.init("", nil, expression, false, expression)
} else {
f.init("", &matcher, expression, true, expression)
}
return f
}
if !found {
if !fc.LabelRe.MatchString(matched) {
// filter name doesn't match, keep searching
continue
}
if value, ok := result["value"]; !ok || value == "" {
// value group not found in the expression
// example: 'label=''
return &invalid
}
operator, found := result["operator"]
if !found {
// used operator is not supported by the filter
// example: @limit=~0
return &invalid
}
if !stringInSlice(fc.SupportedOperators, operator) {
return &invalid
}
@@ -101,13 +107,13 @@ func NewFilter(expression string) FilterT {
if err != nil {
f.init(matched, nil, expression, false, "")
} else {
if value, found := result["value"]; found {
if value != "" {
f.init(matched, &matcher, expression, true, value)
return f
}
f.init(matched, &matcher, expression, false, "")
}
}
return &invalid
}

View File

@@ -406,6 +406,30 @@ var tests = []filterTest{
Expression: "^abb[****].*****",
IsValid: false,
},
filterTest{
Expression: "@silenced=true",
IsValid: false,
},
filterTest{
Expression: "@silenced!=false",
IsValid: false,
},
filterTest{
Expression: "@silenced=~false",
IsValid: false,
},
filterTest{
Expression: "@inhibited=true",
IsValid: false,
},
filterTest{
Expression: "@inhibited!=false",
IsValid: false,
},
filterTest{
Expression: "@inhibited=~false",
IsValid: false,
},
}
func TestFilters(t *testing.T) {

View File

@@ -1,5 +1,7 @@
package filters
import "regexp"
const (
equalOperator string = "="
notEqualOperator string = "!="
@@ -15,6 +17,9 @@ const (
// a===b should yield an error
var matcherRegex = "[=!<>~]+"
// same as matcherRegex but for the filter name part
var filterRegex = "^(@)?[a-zA-Z_][a-zA-Z0-9_]*"
var matcherConfig = map[string]matcherT{
equalOperator: &equalMatcher{},
notEqualOperator: &notEqualMatcher{},
@@ -25,8 +30,8 @@ var matcherConfig = map[string]matcherT{
}
type filterConfig struct {
IsSimple bool
Label string
LabelRe *regexp.Regexp
SupportedOperators []string
Factory newFilterFactory
Autocomplete autocompleteFactory
@@ -37,42 +42,44 @@ type filterConfig struct {
var AllFilters = []filterConfig{
filterConfig{
Label: "@status",
LabelRe: regexp.MustCompile("^@status$"),
SupportedOperators: []string{equalOperator, notEqualOperator},
Factory: newstatusFilter,
Autocomplete: statusAutocomplete,
},
filterConfig{
Label: "@age",
LabelRe: regexp.MustCompile("^@age$"),
SupportedOperators: []string{lessThanOperator, moreThanOperator},
Factory: newAgeFilter,
Autocomplete: ageAutocomplete,
},
filterConfig{
Label: "@silence_jira",
LabelRe: regexp.MustCompile("^@silence_jira$"),
SupportedOperators: []string{regexpOperator, negativeRegexOperator, equalOperator, notEqualOperator},
Factory: newSilenceJiraFilter,
Autocomplete: sinceJiraIDAutocomplete,
},
filterConfig{
Label: "@silence_author",
LabelRe: regexp.MustCompile("^@silence_author$"),
SupportedOperators: []string{regexpOperator, negativeRegexOperator, equalOperator, notEqualOperator},
Factory: newSilenceAuthorFilter,
Autocomplete: sinceAuthorAutocomplete,
},
filterConfig{
Label: "@limit",
LabelRe: regexp.MustCompile("^@limit$"),
SupportedOperators: []string{equalOperator},
Factory: newLimitFilter,
Autocomplete: limitAutocomplete,
},
filterConfig{
Label: "[a-zA-Z_][a-zA-Z0-9_]*",
LabelRe: regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$"),
SupportedOperators: []string{regexpOperator, negativeRegexOperator, equalOperator, notEqualOperator, lessThanOperator, moreThanOperator},
Factory: newLabelFilter,
Autocomplete: labelAutocomplete,
},
filterConfig{
IsSimple: true,
Factory: newFuzzyFilter,
},
}