github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/common/variables/variables.go (about) 1 package variables 2 3 import ( 4 "encoding/json" 5 "strings" 6 7 "github.com/alecthomas/jsonschema" 8 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions" 9 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators" 10 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh" 11 protocolutils "github.com/projectdiscovery/nuclei/v2/pkg/protocols/utils" 12 "github.com/projectdiscovery/nuclei/v2/pkg/types" 13 "github.com/projectdiscovery/nuclei/v2/pkg/utils" 14 stringsutil "github.com/projectdiscovery/utils/strings" 15 ) 16 17 // Variable is a key-value pair of strings that can be used 18 // throughout template. 19 type Variable struct { 20 LazyEval bool `yaml:"-" json:"-"` // LazyEval is used to evaluate variables lazily if it using any expression or global variables 21 utils.InsertionOrderedStringMap `yaml:"-" json:"-"` 22 } 23 24 func (variables Variable) JSONSchemaType() *jsonschema.Type { 25 gotType := &jsonschema.Type{ 26 Type: "object", 27 Title: "variables for the request", 28 Description: "Additional variables for the request", 29 AdditionalProperties: []byte("true"), 30 } 31 return gotType 32 } 33 34 func (variables *Variable) UnmarshalYAML(unmarshal func(interface{}) error) error { 35 variables.InsertionOrderedStringMap = utils.InsertionOrderedStringMap{} 36 if err := unmarshal(&variables.InsertionOrderedStringMap); err != nil { 37 return err 38 } 39 40 if variables.LazyEval || variables.checkForLazyEval() { 41 return nil 42 } 43 44 evaluated := variables.Evaluate(map[string]interface{}{}) 45 46 for k, v := range evaluated { 47 variables.Set(k, v) 48 } 49 return nil 50 } 51 52 func (variables *Variable) UnmarshalJSON(data []byte) error { 53 variables.InsertionOrderedStringMap = utils.InsertionOrderedStringMap{} 54 if err := json.Unmarshal(data, &variables.InsertionOrderedStringMap); err != nil { 55 return err 56 } 57 evaluated := variables.Evaluate(map[string]interface{}{}) 58 59 for k, v := range evaluated { 60 variables.Set(k, v) 61 } 62 return nil 63 } 64 65 // Evaluate returns a finished map of variables based on set values 66 func (variables *Variable) Evaluate(values map[string]interface{}) map[string]interface{} { 67 result := make(map[string]interface{}, variables.Len()) 68 variables.ForEach(func(key string, value interface{}) { 69 valueString := types.ToString(value) 70 combined := generators.MergeMaps(values, result) 71 if value, ok := combined[key]; ok { 72 valueString = types.ToString(value) 73 } 74 result[key] = evaluateVariableValue(valueString, combined, result) 75 }) 76 return result 77 } 78 79 // EvaluateWithInteractsh returns evaluation results of variables with interactsh 80 func (variables *Variable) EvaluateWithInteractsh(values map[string]interface{}, interact *interactsh.Client) (map[string]interface{}, []string) { 81 result := make(map[string]interface{}, variables.Len()) 82 83 var interactURLs []string 84 variables.ForEach(func(key string, value interface{}) { 85 valueString := types.ToString(value) 86 if strings.Contains(valueString, "interactsh-url") { 87 valueString, interactURLs = interact.Replace(valueString, interactURLs) 88 } 89 combined := generators.MergeMaps(values, result) 90 if value, ok := combined[key]; ok { 91 valueString = types.ToString(value) 92 } 93 result[key] = evaluateVariableValue(valueString, combined, result) 94 }) 95 return result, interactURLs 96 } 97 98 // evaluateVariableValue expression and returns final value 99 func evaluateVariableValue(expression string, values, processing map[string]interface{}) string { 100 finalMap := generators.MergeMaps(values, processing) 101 result, err := expressions.Evaluate(expression, finalMap) 102 if err != nil { 103 return expression 104 } 105 106 return result 107 } 108 109 // checkForLazyEval checks if the variables have any lazy evaluation i.e any dsl function 110 // and sets the flag accordingly. 111 func (variables *Variable) checkForLazyEval() bool { 112 variables.ForEach(func(key string, value interface{}) { 113 for _, v := range protocolutils.KnownVariables { 114 if stringsutil.ContainsAny(types.ToString(value), v) { 115 variables.LazyEval = true 116 return 117 } 118 } 119 }) 120 return variables.LazyEval 121 }