github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/common/expressions/variables.go (about) 1 package expressions 2 3 import ( 4 "errors" 5 "regexp" 6 "strings" 7 8 "github.com/Knetic/govaluate" 9 "github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl" 10 ) 11 12 var ( 13 numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`) 14 unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`) 15 ) 16 17 // ContainsUnresolvedVariables returns an error with variable names if the passed 18 // input contains unresolved {{<pattern-here>}} variables. 19 func ContainsUnresolvedVariables(items ...string) error { 20 for _, data := range items { 21 matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1) 22 if len(matches) == 0 { 23 return nil 24 } 25 var unresolvedVariables []string 26 for _, match := range matches { 27 if len(match) < 2 { 28 continue 29 } 30 // Skip if the match is an expression 31 if numericalExpressionRegex.MatchString(match[1]) { 32 continue 33 } 34 // or if it contains only literals (can be solved from expression engine) 35 if hasLiteralsOnly(match[1]) { 36 continue 37 } 38 unresolvedVariables = append(unresolvedVariables, match[1]) 39 } 40 if len(unresolvedVariables) > 0 { 41 return errors.New("unresolved variables found: " + strings.Join(unresolvedVariables, ",")) 42 } 43 } 44 45 return nil 46 } 47 48 // ContainsVariablesWithNames returns an error with variable names if the passed 49 // input contains unresolved {{<pattern-here>}} variables within the provided list 50 func ContainsVariablesWithNames(names map[string]interface{}, items ...string) error { 51 for _, data := range items { 52 matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1) 53 if len(matches) == 0 { 54 return nil 55 } 56 var unresolvedVariables []string 57 for _, match := range matches { 58 if len(match) < 2 { 59 continue 60 } 61 matchName := match[1] 62 // Skip if the match is an expression 63 if numericalExpressionRegex.MatchString(matchName) { 64 continue 65 } 66 // or if it contains only literals (can be solved from expression engine) 67 if hasLiteralsOnly(match[1]) { 68 continue 69 } 70 if _, ok := names[matchName]; !ok { 71 unresolvedVariables = append(unresolvedVariables, matchName) 72 } 73 } 74 if len(unresolvedVariables) > 0 { 75 return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ",")) 76 } 77 } 78 79 return nil 80 } 81 82 // ContainsVariablesWithIgnoreList returns an error with variable names if the passed 83 // input contains unresolved {{<pattern-here>}} other than the ones listed in the ignore list 84 func ContainsVariablesWithIgnoreList(skipNames map[string]interface{}, items ...string) error { 85 var unresolvedVariables []string 86 for _, data := range items { 87 matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1) 88 if len(matches) == 0 { 89 return nil 90 } 91 for _, match := range matches { 92 if len(match) < 2 { 93 continue 94 } 95 matchName := match[1] 96 // Skip if the match is an expression 97 if numericalExpressionRegex.MatchString(matchName) { 98 continue 99 } 100 // or if it contains only literals (can be solved from expression engine) 101 if hasLiteralsOnly(match[1]) { 102 continue 103 } 104 if _, ok := skipNames[matchName]; ok { 105 continue 106 } 107 unresolvedVariables = append(unresolvedVariables, matchName) 108 } 109 } 110 111 if len(unresolvedVariables) > 0 { 112 return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ",")) 113 } 114 115 return nil 116 } 117 118 func hasLiteralsOnly(data string) bool { 119 expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions) 120 if err != nil { 121 return false 122 } 123 if expr != nil { 124 _, err = expr.Evaluate(nil) 125 return err == nil 126 } 127 return true 128 }