mirror of
https://github.com/lunchcat/sif.git
synced 2026-07-28 14:37:01 -07:00
feat(modules): add case-insensitive word matcher option (#319)
This commit is contained in:
@@ -383,7 +383,7 @@ func checkMatcher(m *Matcher, resp *http.Response, body string) bool {
|
||||
return false
|
||||
|
||||
case "word":
|
||||
return checkWords(getPart(m.Part, resp, body), m.Words, m.Condition)
|
||||
return checkWords(getPart(m.Part, resp, body), m.Words, m.Condition, m.CaseInsensitive)
|
||||
|
||||
case "regex":
|
||||
return checkRegex(getPart(m.Part, resp, body), m.Regex, m.Condition)
|
||||
@@ -436,10 +436,19 @@ func getPart(part string, resp *http.Response, body string) string {
|
||||
}
|
||||
|
||||
// checkWords checks if any/all words are found.
|
||||
func checkWords(content string, words []string, condition string) bool {
|
||||
func checkWords(content string, words []string, condition string, caseInsensitive bool) bool {
|
||||
if caseInsensitive {
|
||||
content = strings.ToLower(content)
|
||||
}
|
||||
fold := func(w string) string {
|
||||
if caseInsensitive {
|
||||
return strings.ToLower(w)
|
||||
}
|
||||
return w
|
||||
}
|
||||
if condition == "or" {
|
||||
for _, word := range words {
|
||||
if strings.Contains(content, word) {
|
||||
if strings.Contains(content, fold(word)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -447,7 +456,7 @@ func checkWords(content string, words []string, condition string) bool {
|
||||
}
|
||||
// Default to AND
|
||||
for _, word := range words {
|
||||
if !strings.Contains(content, word) {
|
||||
if !strings.Contains(content, fold(word)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,22 +197,27 @@ func TestCheckWords(t *testing.T) {
|
||||
const content = "alpha beta gamma"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
words []string
|
||||
condition string
|
||||
expect bool
|
||||
name string
|
||||
content string
|
||||
words []string
|
||||
condition string
|
||||
caseInsens bool
|
||||
expect bool
|
||||
}{
|
||||
{name: "and all present", words: []string{"alpha", "gamma"}, condition: "and", expect: true},
|
||||
{name: "and missing", words: []string{"alpha", "delta"}, condition: "and", expect: false},
|
||||
{name: "or present", words: []string{"delta", "beta"}, condition: "or", expect: true},
|
||||
{name: "or absent", words: []string{"delta", "epsilon"}, condition: "or", expect: false},
|
||||
{name: "empty under and matches vacuously", words: nil, condition: "and", expect: true},
|
||||
{name: "empty under or matches nothing", words: nil, condition: "or", expect: false},
|
||||
{name: "and all present", content: content, words: []string{"alpha", "gamma"}, condition: "and", expect: true},
|
||||
{name: "and missing", content: content, words: []string{"alpha", "delta"}, condition: "and", expect: false},
|
||||
{name: "or present", content: content, words: []string{"delta", "beta"}, condition: "or", expect: true},
|
||||
{name: "or absent", content: content, words: []string{"delta", "epsilon"}, condition: "or", expect: false},
|
||||
{name: "empty under and matches vacuously", content: content, words: nil, condition: "and", expect: true},
|
||||
{name: "empty under or matches nothing", content: content, words: nil, condition: "or", expect: false},
|
||||
{name: "case mismatch fails by default", content: "AdMiN panel", words: []string{"admin"}, condition: "or", expect: false},
|
||||
{name: "case-insensitive folds both sides", content: "AdMiN panel", words: []string{"admin"}, condition: "or", caseInsens: true, expect: true},
|
||||
{name: "case-insensitive folds mixed needle", content: "admin panel", words: []string{"AdMiN"}, condition: "or", caseInsens: true, expect: true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := checkWords(content, tt.words, tt.condition); got != tt.expect {
|
||||
if got := checkWords(tt.content, tt.words, tt.condition, tt.caseInsens); got != tt.expect {
|
||||
t.Errorf("checkWords = %v, want %v", got, tt.expect)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -95,6 +95,8 @@ type Matcher struct {
|
||||
Hash []int64 `yaml:"hash,omitempty"` // favicon: shodan mmh3 hashes (signed or unsigned)
|
||||
Condition string `yaml:"condition"` // and, or
|
||||
Negative bool `yaml:"negative"`
|
||||
// CaseInsensitive folds word matching to lower-case when set (word matcher only).
|
||||
CaseInsensitive bool `yaml:"case-insensitive,omitempty"`
|
||||
}
|
||||
|
||||
// Extractor defines data extraction from responses.
|
||||
|
||||
Reference in New Issue
Block a user