Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/operators/matchers/compile.go
2851 views
1
package matchers
2
3
import (
4
"encoding/hex"
5
"fmt"
6
"regexp"
7
"strings"
8
9
"github.com/Knetic/govaluate"
10
"github.com/projectdiscovery/nuclei/v3/pkg/operators/cache"
11
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
12
)
13
14
// CompileMatchers performs the initial setup operation on a matcher
15
func (matcher *Matcher) CompileMatchers() error {
16
var ok bool
17
18
// Support hexadecimal encoding for matchers too.
19
if matcher.Encoding == "hex" {
20
for i, word := range matcher.Words {
21
if decoded, err := hex.DecodeString(word); err == nil && len(decoded) > 0 {
22
matcher.Words[i] = string(decoded)
23
}
24
}
25
}
26
27
// Set up the matcher type
28
computedType, err := toMatcherTypes(matcher.GetType().String())
29
if err != nil {
30
return fmt.Errorf("unknown matcher type specified: %s", matcher.Type)
31
}
32
33
matcher.matcherType = computedType
34
35
// Validate the matcher structure
36
if err := matcher.Validate(); err != nil {
37
return err
38
}
39
40
// By default, match on body if user hasn't provided any specific items
41
if matcher.Part == "" && matcher.GetType() != DSLMatcher {
42
matcher.Part = "body"
43
}
44
45
// Compile the regexes (with shared cache)
46
for _, regex := range matcher.Regex {
47
if cached, err := cache.Regex().GetIFPresent(regex); err == nil && cached != nil {
48
matcher.regexCompiled = append(matcher.regexCompiled, cached)
49
continue
50
}
51
compiled, err := regexp.Compile(regex)
52
if err != nil {
53
return fmt.Errorf("could not compile regex: %s", regex)
54
}
55
_ = cache.Regex().Set(regex, compiled)
56
matcher.regexCompiled = append(matcher.regexCompiled, compiled)
57
}
58
59
// Compile and validate binary Values in matcher
60
for _, value := range matcher.Binary {
61
if decoded, err := hex.DecodeString(value); err != nil {
62
return fmt.Errorf("could not hex decode binary: %s", value)
63
} else {
64
matcher.binaryDecoded = append(matcher.binaryDecoded, string(decoded))
65
}
66
}
67
68
// Compile the dsl expressions (with shared cache)
69
for _, dslExpression := range matcher.DSL {
70
if cached, err := cache.DSL().GetIFPresent(dslExpression); err == nil && cached != nil {
71
matcher.dslCompiled = append(matcher.dslCompiled, cached)
72
continue
73
}
74
compiledExpression, err := govaluate.NewEvaluableExpressionWithFunctions(dslExpression, dsl.HelperFunctions)
75
if err != nil {
76
return &dsl.CompilationError{DslSignature: dslExpression, WrappedError: err}
77
}
78
_ = cache.DSL().Set(dslExpression, compiledExpression)
79
matcher.dslCompiled = append(matcher.dslCompiled, compiledExpression)
80
}
81
82
// Set up the condition type, if any.
83
if matcher.Condition != "" {
84
matcher.condition, ok = ConditionTypes[matcher.Condition]
85
if !ok {
86
return fmt.Errorf("unknown condition specified: %s", matcher.Condition)
87
}
88
} else {
89
matcher.condition = ORCondition
90
}
91
92
if matcher.CaseInsensitive {
93
if matcher.GetType() != WordsMatcher {
94
return fmt.Errorf("case-insensitive flag is supported only for 'word' matchers (not '%s')", matcher.Type)
95
}
96
for i := range matcher.Words {
97
matcher.Words[i] = strings.ToLower(matcher.Words[i])
98
}
99
}
100
return nil
101
}
102
103
// GetType returns the condition type of the matcher
104
// todo: the field should be exposed natively
105
func (matcher *Matcher) GetCondition() ConditionType {
106
return matcher.condition
107
}
108
109