forked from projectdiscovery/nuclei
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathworkflows.go
More file actions
139 lines (126 loc) · 4.63 KB
/
workflows.go
File metadata and controls
139 lines (126 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package templates
import (
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/keys"
"github.com/projectdiscovery/nuclei/v3/pkg/model"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/stats"
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
)
// compileWorkflow compiles the workflow for execution
func compileWorkflow(path string, preprocessor Preprocessor, options *protocols.ExecutorOptions, workflow *workflows.Workflow, loader model.WorkflowLoader) {
for _, workflow := range workflow.Workflows {
if err := parseWorkflow(preprocessor, workflow, options, loader); err != nil {
gologger.Warning().Msgf("Could not parse workflow %s: %v\n", path, err)
continue
}
}
}
// parseWorkflow parses and compiles all templates in a workflow recursively
func parseWorkflow(preprocessor Preprocessor, workflow *workflows.WorkflowTemplate, options *protocols.ExecutorOptions, loader model.WorkflowLoader) error {
shouldNotValidate := false
if workflow.Template == "" && workflow.Tags.IsEmpty() {
return errors.New("invalid workflow with no templates or tags")
}
if len(workflow.Subtemplates) > 0 || len(workflow.Matchers) > 0 {
shouldNotValidate = true
}
if err := parseWorkflowTemplate(workflow, preprocessor, options, loader, shouldNotValidate); err != nil {
return err
}
for _, subtemplates := range workflow.Subtemplates {
if err := parseWorkflow(preprocessor, subtemplates, options, loader); err != nil {
gologger.Warning().Msgf("Could not parse workflow: %v\n", err)
continue
}
}
for _, matcher := range workflow.Matchers {
if len(matcher.Name.ToSlice()) > 0 {
if err := matcher.Compile(); err != nil {
return errors.Wrap(err, "could not compile workflow matcher")
}
}
for _, subtemplates := range matcher.Subtemplates {
if err := parseWorkflow(preprocessor, subtemplates, options, loader); err != nil {
gologger.Warning().Msgf("Could not parse workflow: %v\n", err)
continue
}
}
}
return nil
}
// parseWorkflowTemplate parses a workflow template creating an executer
func parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, preprocessor Preprocessor, options *protocols.ExecutorOptions, loader model.WorkflowLoader, noValidate bool) error {
var paths []string
subTemplateTags := workflow.Tags
if !subTemplateTags.IsEmpty() {
paths = loader.GetTemplatePathsByTags(subTemplateTags.ToSlice())
} else {
paths = loader.GetTemplatePaths([]string{workflow.Template}, noValidate)
}
if len(paths) == 0 {
return nil
}
var workflowTemplates []*Template
for _, path := range paths {
template, err := Parse(path, preprocessor, options.Copy())
if err != nil {
gologger.Warning().Msgf("Could not parse workflow template %s: %v\n", path, err)
continue
}
if template == nil {
continue
}
if template.Executer == nil {
gologger.Warning().Msgf("Could not parse workflow template %s: no executer found\n", path)
continue
}
if options.Options.DisableUnsignedTemplates && !template.Verified {
// skip unverified templates when prompted to do so
stats.Increment(SkippedUnsignedStats)
continue
}
if template.UsesRequestSignature() && !template.Verified {
stats.Increment(SkippedRequestSignatureStats)
continue
}
if template.HasCodeRequest() {
if !options.Options.EnableCodeTemplates {
// NOTE(dwisiswant0): It is safe to continue here during
// validation mode, because the template has already been parsed
// and syntax-validated by templates.Parse() above. It only
// prevents adding to workflow's executer list and suppresses
// warning messages.
if !options.Options.Validate {
gologger.Warning().Msgf("`-code` flag not found, skipping code template from workflow: %v\n", path)
}
continue
} else if !template.Verified {
// unverified code templates are not allowed in workflows
gologger.Warning().Msgf("skipping unverified code template from workflow: %v\n", path)
continue
}
}
// increment signed/unsigned counters
if template.Verified {
if template.TemplateVerifier == "" {
SignatureStats[keys.PDVerifier].Add(1)
} else {
SignatureStats[template.TemplateVerifier].Add(1)
}
} else {
SignatureStats[Unsigned].Add(1)
}
workflowTemplates = append(workflowTemplates, template)
}
finalTemplates, _, _ := ClusterTemplates(workflowTemplates, options.Copy())
for _, template := range finalTemplates {
workflow.Executers = append(workflow.Executers, &workflows.ProtocolExecuterPair{
Executer: template.Executer,
Options: options,
TemplateType: template.Type(),
})
}
return nil
}