github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/templates/workflows.go (about)

     1  package templates
     2  
     3  import (
     4  	"github.com/pkg/errors"
     5  
     6  	"github.com/projectdiscovery/gologger"
     7  	"github.com/projectdiscovery/nuclei/v2/pkg/model"
     8  	"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
     9  	"github.com/projectdiscovery/nuclei/v2/pkg/workflows"
    10  )
    11  
    12  // compileWorkflow compiles the workflow for execution
    13  func compileWorkflow(path string, preprocessor Preprocessor, options *protocols.ExecutorOptions, workflow *workflows.Workflow, loader model.WorkflowLoader) {
    14  	for _, workflow := range workflow.Workflows {
    15  		if err := parseWorkflow(preprocessor, workflow, options, loader); err != nil {
    16  			gologger.Warning().Msgf("Could not parse workflow %s: %v\n", path, err)
    17  			continue
    18  		}
    19  	}
    20  }
    21  
    22  // parseWorkflow parses and compiles all templates in a workflow recursively
    23  func parseWorkflow(preprocessor Preprocessor, workflow *workflows.WorkflowTemplate, options *protocols.ExecutorOptions, loader model.WorkflowLoader) error {
    24  	shouldNotValidate := false
    25  
    26  	if workflow.Template == "" && workflow.Tags.IsEmpty() {
    27  		return errors.New("invalid workflow with no templates or tags")
    28  	}
    29  	if len(workflow.Subtemplates) > 0 || len(workflow.Matchers) > 0 {
    30  		shouldNotValidate = true
    31  	}
    32  	if err := parseWorkflowTemplate(workflow, preprocessor, options, loader, shouldNotValidate); err != nil {
    33  		return err
    34  	}
    35  	for _, subtemplates := range workflow.Subtemplates {
    36  		if err := parseWorkflow(preprocessor, subtemplates, options, loader); err != nil {
    37  			gologger.Warning().Msgf("Could not parse workflow: %v\n", err)
    38  			continue
    39  		}
    40  	}
    41  	for _, matcher := range workflow.Matchers {
    42  		if len(matcher.Name.ToSlice()) > 0 {
    43  			if err := matcher.Compile(); err != nil {
    44  				return errors.Wrap(err, "could not compile workflow matcher")
    45  			}
    46  		}
    47  		for _, subtemplates := range matcher.Subtemplates {
    48  			if err := parseWorkflow(preprocessor, subtemplates, options, loader); err != nil {
    49  				gologger.Warning().Msgf("Could not parse workflow: %v\n", err)
    50  				continue
    51  			}
    52  		}
    53  	}
    54  	return nil
    55  }
    56  
    57  // parseWorkflowTemplate parses a workflow template creating an executer
    58  func parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, preprocessor Preprocessor, options *protocols.ExecutorOptions, loader model.WorkflowLoader, noValidate bool) error {
    59  	var paths []string
    60  
    61  	subTemplateTags := workflow.Tags
    62  	if !subTemplateTags.IsEmpty() {
    63  		paths = loader.GetTemplatePathsByTags(subTemplateTags.ToSlice())
    64  	} else {
    65  		paths = loader.GetTemplatePaths([]string{workflow.Template}, noValidate)
    66  	}
    67  	if len(paths) == 0 {
    68  		return nil
    69  	}
    70  
    71  	var workflowTemplates []*Template
    72  
    73  	for _, path := range paths {
    74  		template, err := Parse(path, preprocessor, options.Copy())
    75  		if err != nil {
    76  			gologger.Warning().Msgf("Could not parse workflow template %s: %v\n", path, err)
    77  			continue
    78  		}
    79  		if template.Executer == nil {
    80  			gologger.Warning().Msgf("Could not parse workflow template %s: no executer found\n", path)
    81  			continue
    82  		}
    83  		workflowTemplates = append(workflowTemplates, template)
    84  	}
    85  
    86  	finalTemplates, _ := ClusterTemplates(workflowTemplates, options.Copy())
    87  	for _, template := range finalTemplates {
    88  		workflow.Executers = append(workflow.Executers, &workflows.ProtocolExecuterPair{
    89  			Executer:     template.Executer,
    90  			Options:      options,
    91  			TemplateType: template.Type(),
    92  		})
    93  	}
    94  
    95  	return nil
    96  }