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 }