2021-10-07 01:40:49 +05:30
|
|
|
package expressions
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
2022-08-23 13:16:41 +05:30
|
|
|
|
|
|
|
|
"github.com/Knetic/govaluate"
|
2023-10-17 17:44:13 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
|
2021-10-07 01:40:49 +05:30
|
|
|
)
|
|
|
|
|
|
2022-02-28 22:19:51 +05:30
|
|
|
var (
|
2022-08-17 05:29:51 +05:30
|
|
|
numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`)
|
2022-02-28 22:19:51 +05:30
|
|
|
unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`)
|
|
|
|
|
)
|
2021-10-07 01:40:49 +05:30
|
|
|
|
|
|
|
|
// ContainsUnresolvedVariables returns an error with variable names if the passed
|
|
|
|
|
// input contains unresolved {{<pattern-here>}} variables.
|
2021-11-18 14:52:11 +01:00
|
|
|
func ContainsUnresolvedVariables(items ...string) error {
|
|
|
|
|
for _, data := range items {
|
|
|
|
|
matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
return nil
|
2021-10-07 01:40:49 +05:30
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
var unresolvedVariables []string
|
|
|
|
|
for _, match := range matches {
|
2021-11-18 14:52:11 +01:00
|
|
|
if len(match) < 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-02-28 22:19:51 +05:30
|
|
|
// Skip if the match is an expression
|
|
|
|
|
if numericalExpressionRegex.MatchString(match[1]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-06-13 10:25:06 +02:00
|
|
|
// or if it contains only literals (can be solved from expression engine)
|
|
|
|
|
if hasLiteralsOnly(match[1]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
unresolvedVariables = append(unresolvedVariables, match[1])
|
2021-10-07 01:40:49 +05:30
|
|
|
}
|
2022-01-09 13:39:50 +01:00
|
|
|
if len(unresolvedVariables) > 0 {
|
|
|
|
|
return errors.New("unresolved variables found: " + strings.Join(unresolvedVariables, ","))
|
|
|
|
|
}
|
2021-10-07 01:40:49 +05:30
|
|
|
}
|
2021-10-07 12:36:27 +02:00
|
|
|
|
2021-11-18 14:52:11 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
2021-10-07 12:36:27 +02:00
|
|
|
|
2021-12-18 20:06:51 +01:00
|
|
|
// ContainsVariablesWithNames returns an error with variable names if the passed
|
|
|
|
|
// input contains unresolved {{<pattern-here>}} variables within the provided list
|
2021-11-18 14:52:11 +01:00
|
|
|
func ContainsVariablesWithNames(names map[string]interface{}, items ...string) error {
|
|
|
|
|
for _, data := range items {
|
|
|
|
|
matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
return nil
|
2021-10-07 12:36:27 +02:00
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
var unresolvedVariables []string
|
|
|
|
|
for _, match := range matches {
|
2021-11-18 14:52:11 +01:00
|
|
|
if len(match) < 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
matchName := match[1]
|
2022-02-28 22:19:51 +05:30
|
|
|
// Skip if the match is an expression
|
|
|
|
|
if numericalExpressionRegex.MatchString(matchName) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-06-13 10:25:06 +02:00
|
|
|
// or if it contains only literals (can be solved from expression engine)
|
|
|
|
|
if hasLiteralsOnly(match[1]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-11-18 14:52:11 +01:00
|
|
|
if _, ok := names[matchName]; !ok {
|
2021-12-18 20:06:51 +01:00
|
|
|
unresolvedVariables = append(unresolvedVariables, matchName)
|
2021-10-07 12:36:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 13:39:50 +01:00
|
|
|
if len(unresolvedVariables) > 0 {
|
|
|
|
|
return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))
|
|
|
|
|
}
|
2021-10-07 12:36:27 +02:00
|
|
|
}
|
2021-11-18 14:52:11 +01:00
|
|
|
|
|
|
|
|
return nil
|
2021-10-07 12:36:27 +02:00
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
|
|
|
|
|
// ContainsVariablesWithIgnoreList returns an error with variable names if the passed
|
|
|
|
|
// input contains unresolved {{<pattern-here>}} other than the ones listed in the ignore list
|
|
|
|
|
func ContainsVariablesWithIgnoreList(skipNames map[string]interface{}, items ...string) error {
|
|
|
|
|
var unresolvedVariables []string
|
|
|
|
|
for _, data := range items {
|
|
|
|
|
matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)
|
|
|
|
|
if len(matches) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
for _, match := range matches {
|
|
|
|
|
if len(match) < 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
matchName := match[1]
|
2022-02-28 22:19:51 +05:30
|
|
|
// Skip if the match is an expression
|
|
|
|
|
if numericalExpressionRegex.MatchString(matchName) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-06-13 10:25:06 +02:00
|
|
|
// or if it contains only literals (can be solved from expression engine)
|
|
|
|
|
if hasLiteralsOnly(match[1]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-12-18 20:06:51 +01:00
|
|
|
if _, ok := skipNames[matchName]; ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
unresolvedVariables = append(unresolvedVariables, matchName)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(unresolvedVariables) > 0 {
|
|
|
|
|
return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))
|
|
|
|
|
}
|
2022-01-09 13:39:50 +01:00
|
|
|
|
2021-12-18 20:06:51 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
2022-08-23 13:16:41 +05:30
|
|
|
|
|
|
|
|
func hasLiteralsOnly(data string) bool {
|
|
|
|
|
expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)
|
2022-11-01 20:28:50 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-07-14 17:54:12 +02:00
|
|
|
if expr != nil {
|
2022-08-23 13:16:41 +05:30
|
|
|
_, err = expr.Evaluate(nil)
|
|
|
|
|
return err == nil
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|