Path: blob/dev/pkg/protocols/common/expressions/variables.go
2072 views
package expressions12import (3"errors"4"regexp"5"strings"67"github.com/Knetic/govaluate"8"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"9)1011var (12numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`)13unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`)14)1516// ContainsUnresolvedVariables returns an error with variable names if the passed17// input contains unresolved {{<pattern-here>}} variables.18func ContainsUnresolvedVariables(items ...string) error {19for _, data := range items {20matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)21if len(matches) == 0 {22return nil23}24var unresolvedVariables []string25for _, match := range matches {26if len(match) < 2 {27continue28}29// Skip if the match is an expression30if numericalExpressionRegex.MatchString(match[1]) {31continue32}33// or if it contains only literals (can be solved from expression engine)34if hasLiteralsOnly(match[1]) {35continue36}37unresolvedVariables = append(unresolvedVariables, match[1])38}39if len(unresolvedVariables) > 0 {40return errors.New("unresolved variables found: " + strings.Join(unresolvedVariables, ","))41}42}4344return nil45}4647// ContainsVariablesWithNames returns an error with variable names if the passed48// input contains unresolved {{<pattern-here>}} variables within the provided list49func ContainsVariablesWithNames(names map[string]interface{}, items ...string) error {50for _, data := range items {51matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)52if len(matches) == 0 {53return nil54}55var unresolvedVariables []string56for _, match := range matches {57if len(match) < 2 {58continue59}60matchName := match[1]61// Skip if the match is an expression62if numericalExpressionRegex.MatchString(matchName) {63continue64}65// or if it contains only literals (can be solved from expression engine)66if hasLiteralsOnly(match[1]) {67continue68}69if _, ok := names[matchName]; !ok {70unresolvedVariables = append(unresolvedVariables, matchName)71}72}73if len(unresolvedVariables) > 0 {74return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))75}76}7778return nil79}8081// ContainsVariablesWithIgnoreList returns an error with variable names if the passed82// input contains unresolved {{<pattern-here>}} other than the ones listed in the ignore list83func ContainsVariablesWithIgnoreList(skipNames map[string]interface{}, items ...string) error {84var unresolvedVariables []string85for _, data := range items {86matches := unresolvedVariablesRegex.FindAllStringSubmatch(data, -1)87if len(matches) == 0 {88return nil89}90for _, match := range matches {91if len(match) < 2 {92continue93}94matchName := match[1]95// Skip if the match is an expression96if numericalExpressionRegex.MatchString(matchName) {97continue98}99// or if it contains only literals (can be solved from expression engine)100if hasLiteralsOnly(match[1]) {101continue102}103if _, ok := skipNames[matchName]; ok {104continue105}106unresolvedVariables = append(unresolvedVariables, matchName)107}108}109110if len(unresolvedVariables) > 0 {111return errors.New("unresolved variables with values found: " + strings.Join(unresolvedVariables, ","))112}113114return nil115}116117func hasLiteralsOnly(data string) bool {118expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)119if err != nil {120return false121}122if expr != nil {123_, err = expr.Evaluate(nil)124return err == nil125}126return true127}128129130