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  }