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
|
return false
|
||||||
|
|
||||||
case "word":
|
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":
|
case "regex":
|
||||||
return checkRegex(getPart(m.Part, resp, body), m.Regex, m.Condition)
|
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.
|
// 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" {
|
if condition == "or" {
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
if strings.Contains(content, word) {
|
if strings.Contains(content, fold(word)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +456,7 @@ func checkWords(content string, words []string, condition string) bool {
|
|||||||
}
|
}
|
||||||
// Default to AND
|
// Default to AND
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
if !strings.Contains(content, word) {
|
if !strings.Contains(content, fold(word)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,22 +197,27 @@ func TestCheckWords(t *testing.T) {
|
|||||||
const content = "alpha beta gamma"
|
const content = "alpha beta gamma"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
words []string
|
content string
|
||||||
condition string
|
words []string
|
||||||
expect bool
|
condition string
|
||||||
|
caseInsens bool
|
||||||
|
expect bool
|
||||||
}{
|
}{
|
||||||
{name: "and all present", words: []string{"alpha", "gamma"}, condition: "and", expect: true},
|
{name: "and all present", content: content, words: []string{"alpha", "gamma"}, condition: "and", expect: true},
|
||||||
{name: "and missing", words: []string{"alpha", "delta"}, condition: "and", expect: false},
|
{name: "and missing", content: content, words: []string{"alpha", "delta"}, condition: "and", expect: false},
|
||||||
{name: "or present", words: []string{"delta", "beta"}, condition: "or", expect: true},
|
{name: "or present", content: content, words: []string{"delta", "beta"}, condition: "or", expect: true},
|
||||||
{name: "or absent", words: []string{"delta", "epsilon"}, condition: "or", expect: false},
|
{name: "or absent", content: content, words: []string{"delta", "epsilon"}, condition: "or", expect: false},
|
||||||
{name: "empty under and matches vacuously", words: nil, condition: "and", expect: true},
|
{name: "empty under and matches vacuously", content: content, words: nil, condition: "and", expect: true},
|
||||||
{name: "empty under or matches nothing", words: nil, condition: "or", expect: false},
|
{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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
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)
|
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)
|
Hash []int64 `yaml:"hash,omitempty"` // favicon: shodan mmh3 hashes (signed or unsigned)
|
||||||
Condition string `yaml:"condition"` // and, or
|
Condition string `yaml:"condition"` // and, or
|
||||||
Negative bool `yaml:"negative"`
|
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.
|
// Extractor defines data extraction from responses.
|
||||||
|
|||||||
Reference in New Issue
Block a user