Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/catalog/loader/loader.go
2070 views
1
package loader
2
3
import (
4
"fmt"
5
"io"
6
"net/url"
7
"os"
8
"sort"
9
"strings"
10
11
"github.com/logrusorgru/aurora"
12
"github.com/pkg/errors"
13
"github.com/projectdiscovery/gologger"
14
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
15
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
16
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader/filter"
17
"github.com/projectdiscovery/nuclei/v3/pkg/keys"
18
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
19
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
20
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
21
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
22
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
23
"github.com/projectdiscovery/nuclei/v3/pkg/types"
24
"github.com/projectdiscovery/nuclei/v3/pkg/utils/stats"
25
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
26
"github.com/projectdiscovery/retryablehttp-go"
27
"github.com/projectdiscovery/utils/errkit"
28
sliceutil "github.com/projectdiscovery/utils/slice"
29
stringsutil "github.com/projectdiscovery/utils/strings"
30
syncutil "github.com/projectdiscovery/utils/sync"
31
urlutil "github.com/projectdiscovery/utils/url"
32
"github.com/rs/xid"
33
)
34
35
const (
36
httpPrefix = "http://"
37
httpsPrefix = "https://"
38
AuthStoreId = "auth_store"
39
)
40
41
var (
42
TrustedTemplateDomains = []string{"cloud.projectdiscovery.io"}
43
)
44
45
// Config contains the configuration options for the loader
46
type Config struct {
47
StoreId string // used to set store id (optional)
48
Templates []string
49
TemplateURLs []string
50
Workflows []string
51
WorkflowURLs []string
52
ExcludeTemplates []string
53
IncludeTemplates []string
54
RemoteTemplateDomainList []string
55
AITemplatePrompt string
56
57
Tags []string
58
ExcludeTags []string
59
Protocols templateTypes.ProtocolTypes
60
ExcludeProtocols templateTypes.ProtocolTypes
61
Authors []string
62
Severities severity.Severities
63
ExcludeSeverities severity.Severities
64
IncludeTags []string
65
IncludeIds []string
66
ExcludeIds []string
67
IncludeConditions []string
68
69
Catalog catalog.Catalog
70
ExecutorOptions *protocols.ExecutorOptions
71
Logger *gologger.Logger
72
}
73
74
// Store is a storage for loaded nuclei templates
75
type Store struct {
76
id string // id of the store (optional)
77
tagFilter *templates.TagFilter
78
pathFilter *filter.PathFilter
79
config *Config
80
finalTemplates []string
81
finalWorkflows []string
82
83
templates []*templates.Template
84
workflows []*templates.Template
85
86
preprocessor templates.Preprocessor
87
88
logger *gologger.Logger
89
90
// NotFoundCallback is called for each not found template
91
// This overrides error handling for not found templates
92
NotFoundCallback func(template string) bool
93
}
94
95
// NewConfig returns a new loader config
96
func NewConfig(options *types.Options, catalog catalog.Catalog, executerOpts *protocols.ExecutorOptions) *Config {
97
loaderConfig := Config{
98
Templates: options.Templates,
99
Workflows: options.Workflows,
100
RemoteTemplateDomainList: options.RemoteTemplateDomainList,
101
TemplateURLs: options.TemplateURLs,
102
WorkflowURLs: options.WorkflowURLs,
103
ExcludeTemplates: options.ExcludedTemplates,
104
Tags: options.Tags,
105
ExcludeTags: options.ExcludeTags,
106
IncludeTemplates: options.IncludeTemplates,
107
Authors: options.Authors,
108
Severities: options.Severities,
109
ExcludeSeverities: options.ExcludeSeverities,
110
IncludeTags: options.IncludeTags,
111
IncludeIds: options.IncludeIds,
112
ExcludeIds: options.ExcludeIds,
113
Protocols: options.Protocols,
114
ExcludeProtocols: options.ExcludeProtocols,
115
IncludeConditions: options.IncludeConditions,
116
Catalog: catalog,
117
ExecutorOptions: executerOpts,
118
AITemplatePrompt: options.AITemplatePrompt,
119
Logger: options.Logger,
120
}
121
loaderConfig.RemoteTemplateDomainList = append(loaderConfig.RemoteTemplateDomainList, TrustedTemplateDomains...)
122
return &loaderConfig
123
}
124
125
// New creates a new template store based on provided configuration
126
func New(cfg *Config) (*Store, error) {
127
tagFilter, err := templates.NewTagFilter(&templates.TagFilterConfig{
128
Tags: cfg.Tags,
129
ExcludeTags: cfg.ExcludeTags,
130
Authors: cfg.Authors,
131
Severities: cfg.Severities,
132
ExcludeSeverities: cfg.ExcludeSeverities,
133
IncludeTags: cfg.IncludeTags,
134
IncludeIds: cfg.IncludeIds,
135
ExcludeIds: cfg.ExcludeIds,
136
Protocols: cfg.Protocols,
137
ExcludeProtocols: cfg.ExcludeProtocols,
138
IncludeConditions: cfg.IncludeConditions,
139
})
140
if err != nil {
141
return nil, err
142
}
143
144
store := &Store{
145
id: cfg.StoreId,
146
config: cfg,
147
tagFilter: tagFilter,
148
pathFilter: filter.NewPathFilter(&filter.PathFilterConfig{
149
IncludedTemplates: cfg.IncludeTemplates,
150
ExcludedTemplates: cfg.ExcludeTemplates,
151
}, cfg.Catalog),
152
finalTemplates: cfg.Templates,
153
finalWorkflows: cfg.Workflows,
154
logger: cfg.Logger,
155
}
156
157
// Do a check to see if we have URLs in templates flag, if so
158
// we need to processs them separately and remove them from the initial list
159
var templatesFinal []string
160
for _, template := range cfg.Templates {
161
// TODO: Add and replace this with urlutil.IsURL() helper
162
if stringsutil.HasPrefixAny(template, httpPrefix, httpsPrefix) {
163
cfg.TemplateURLs = append(cfg.TemplateURLs, template)
164
} else {
165
templatesFinal = append(templatesFinal, template)
166
}
167
}
168
169
// fix editor paths
170
remoteTemplates := []string{}
171
for _, v := range cfg.TemplateURLs {
172
if _, err := urlutil.Parse(v); err == nil {
173
remoteTemplates = append(remoteTemplates, handleTemplatesEditorURLs(v))
174
} else {
175
templatesFinal = append(templatesFinal, v) // something went wrong, treat it as a file
176
}
177
}
178
cfg.TemplateURLs = remoteTemplates
179
store.finalTemplates = templatesFinal
180
181
urlBasedTemplatesProvided := len(cfg.TemplateURLs) > 0 || len(cfg.WorkflowURLs) > 0
182
if urlBasedTemplatesProvided {
183
remoteTemplates, remoteWorkflows, err := getRemoteTemplatesAndWorkflows(cfg.TemplateURLs, cfg.WorkflowURLs, cfg.RemoteTemplateDomainList)
184
if err != nil {
185
return store, err
186
}
187
store.finalTemplates = append(store.finalTemplates, remoteTemplates...)
188
store.finalWorkflows = append(store.finalWorkflows, remoteWorkflows...)
189
}
190
191
// Handle AI template generation if prompt is provided
192
if len(cfg.AITemplatePrompt) > 0 {
193
aiTemplates, err := getAIGeneratedTemplates(cfg.AITemplatePrompt, cfg.ExecutorOptions.Options)
194
if err != nil {
195
return nil, err
196
}
197
store.finalTemplates = append(store.finalTemplates, aiTemplates...)
198
}
199
200
// Handle a dot as the current working directory
201
if len(store.finalTemplates) == 1 && store.finalTemplates[0] == "." {
202
currentDirectory, err := os.Getwd()
203
if err != nil {
204
return nil, errors.Wrap(err, "could not get current directory")
205
}
206
store.finalTemplates = []string{currentDirectory}
207
}
208
209
// Handle a case with no templates or workflows, where we use base directory
210
if len(store.finalTemplates) == 0 && len(store.finalWorkflows) == 0 && !urlBasedTemplatesProvided {
211
store.finalTemplates = []string{config.DefaultConfig.TemplatesDirectory}
212
}
213
214
return store, nil
215
}
216
217
func handleTemplatesEditorURLs(input string) string {
218
parsed, err := url.Parse(input)
219
if err != nil {
220
return input
221
}
222
if !strings.HasSuffix(parsed.Hostname(), "cloud.projectdiscovery.io") {
223
return input
224
}
225
if strings.HasSuffix(parsed.Path, ".yaml") {
226
return input
227
}
228
parsed.Path = fmt.Sprintf("%s.yaml", parsed.Path)
229
finalURL := parsed.String()
230
return finalURL
231
}
232
233
// ReadTemplateFromURI should only be used for viewing templates
234
// and should not be used anywhere else like loading and executing templates
235
// there is no sandbox restriction here
236
func (store *Store) ReadTemplateFromURI(uri string, remote bool) ([]byte, error) {
237
if stringsutil.HasPrefixAny(uri, httpPrefix, httpsPrefix) && remote {
238
uri = handleTemplatesEditorURLs(uri)
239
remoteTemplates, _, err := getRemoteTemplatesAndWorkflows([]string{uri}, nil, store.config.RemoteTemplateDomainList)
240
if err != nil || len(remoteTemplates) == 0 {
241
return nil, errkit.Wrapf(err, "Could not load template %s: got %v", uri, remoteTemplates)
242
}
243
resp, err := retryablehttp.Get(remoteTemplates[0])
244
if err != nil {
245
return nil, err
246
}
247
defer func() {
248
_ = resp.Body.Close()
249
}()
250
return io.ReadAll(resp.Body)
251
} else {
252
return os.ReadFile(uri)
253
}
254
}
255
256
func (store *Store) ID() string {
257
return store.id
258
}
259
260
// Templates returns all the templates in the store
261
func (store *Store) Templates() []*templates.Template {
262
return store.templates
263
}
264
265
// Workflows returns all the workflows in the store
266
func (store *Store) Workflows() []*templates.Template {
267
return store.workflows
268
}
269
270
// RegisterPreprocessor allows a custom preprocessor to be passed to the store to run against templates
271
func (store *Store) RegisterPreprocessor(preprocessor templates.Preprocessor) {
272
store.preprocessor = preprocessor
273
}
274
275
// Load loads all the templates from a store, performs filtering and returns
276
// the complete compiled templates for a nuclei execution configuration.
277
func (store *Store) Load() {
278
store.templates = store.LoadTemplates(store.finalTemplates)
279
store.workflows = store.LoadWorkflows(store.finalWorkflows)
280
}
281
282
var templateIDPathMap map[string]string
283
284
func init() {
285
templateIDPathMap = make(map[string]string)
286
}
287
288
// LoadTemplatesOnlyMetadata loads only the metadata of the templates
289
func (store *Store) LoadTemplatesOnlyMetadata() error {
290
templatePaths, errs := store.config.Catalog.GetTemplatesPath(store.finalTemplates)
291
store.logErroredTemplates(errs)
292
293
filteredTemplatePaths := store.pathFilter.Match(templatePaths)
294
295
validPaths := make(map[string]struct{})
296
for templatePath := range filteredTemplatePaths {
297
loaded, err := store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, nil, store.config.Catalog)
298
if loaded || store.pathFilter.MatchIncluded(templatePath) {
299
validPaths[templatePath] = struct{}{}
300
}
301
if err != nil {
302
if strings.Contains(err.Error(), templates.ErrExcluded.Error()) {
303
stats.Increment(templates.TemplatesExcludedStats)
304
if config.DefaultConfig.LogAllEvents {
305
store.logger.Print().Msgf("[%v] %v\n", aurora.Yellow("WRN").String(), err.Error())
306
}
307
continue
308
}
309
store.logger.Warning().Msg(err.Error())
310
}
311
}
312
parserItem, ok := store.config.ExecutorOptions.Parser.(*templates.Parser)
313
if !ok {
314
return errors.New("invalid parser")
315
}
316
templatesCache := parserItem.Cache()
317
318
for templatePath := range validPaths {
319
template, _, _ := templatesCache.Has(templatePath)
320
321
if len(template.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
322
continue
323
}
324
325
if len(template.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
326
continue
327
}
328
329
if template.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
330
continue
331
}
332
333
if template.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
334
continue
335
}
336
337
if template.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
338
continue
339
}
340
341
if template != nil {
342
template.Path = templatePath
343
store.templates = append(store.templates, template)
344
}
345
}
346
return nil
347
}
348
349
// ValidateTemplates takes a list of templates and validates them
350
// erroring out on discovering any faulty templates.
351
func (store *Store) ValidateTemplates() error {
352
templatePaths, errs := store.config.Catalog.GetTemplatesPath(store.finalTemplates)
353
store.logErroredTemplates(errs)
354
workflowPaths, errs := store.config.Catalog.GetTemplatesPath(store.finalWorkflows)
355
store.logErroredTemplates(errs)
356
357
filteredTemplatePaths := store.pathFilter.Match(templatePaths)
358
filteredWorkflowPaths := store.pathFilter.Match(workflowPaths)
359
360
if store.areTemplatesValid(filteredTemplatePaths) && store.areWorkflowsValid(filteredWorkflowPaths) {
361
return nil
362
}
363
return errors.New("errors occurred during template validation")
364
}
365
366
func (store *Store) areWorkflowsValid(filteredWorkflowPaths map[string]struct{}) bool {
367
return store.areWorkflowOrTemplatesValid(filteredWorkflowPaths, true, func(templatePath string, tagFilter *templates.TagFilter) (bool, error) {
368
return store.config.ExecutorOptions.Parser.LoadWorkflow(templatePath, store.config.Catalog)
369
})
370
}
371
372
func (store *Store) areTemplatesValid(filteredTemplatePaths map[string]struct{}) bool {
373
return store.areWorkflowOrTemplatesValid(filteredTemplatePaths, false, func(templatePath string, tagFilter *templates.TagFilter) (bool, error) {
374
return store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, nil, store.config.Catalog)
375
})
376
}
377
378
func (store *Store) areWorkflowOrTemplatesValid(filteredTemplatePaths map[string]struct{}, isWorkflow bool, load func(templatePath string, tagFilter *templates.TagFilter) (bool, error)) bool {
379
areTemplatesValid := true
380
381
for templatePath := range filteredTemplatePaths {
382
if _, err := load(templatePath, store.tagFilter); err != nil {
383
if isParsingError(store, "Error occurred loading template %s: %s\n", templatePath, err) {
384
areTemplatesValid = false
385
continue
386
}
387
}
388
389
template, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
390
if err != nil {
391
if isParsingError(store, "Error occurred parsing template %s: %s\n", templatePath, err) {
392
areTemplatesValid = false
393
continue
394
}
395
} else if template == nil {
396
// NOTE(dwisiswant0): possibly global matchers template.
397
// This could definitely be handled better, for example by returning an
398
// `ErrGlobalMatchersTemplate` during `templates.Parse` and checking it
399
// with `errors.Is`.
400
//
401
// However, I'm not sure if every reference to it should be handled
402
// that way. Returning a `templates.Template` pointer would mean it's
403
// an active template (sending requests), and adding a specific field
404
// like `isGlobalMatchers` in `templates.Template` (then checking it
405
// with a `*templates.Template.IsGlobalMatchersEnabled` method) would
406
// just introduce more unknown issues - like during template
407
// clustering, AFAIK.
408
continue
409
} else {
410
if existingTemplatePath, found := templateIDPathMap[template.ID]; !found {
411
templateIDPathMap[template.ID] = templatePath
412
} else {
413
// TODO: until https://github.com/projectdiscovery/nuclei-templates/issues/11324 is deployed
414
// disable strict validation to allow GH actions to run
415
// areTemplatesValid = false
416
store.logger.Warning().Msgf("Found duplicate template ID during validation '%s' => '%s': %s\n", templatePath, existingTemplatePath, template.ID)
417
}
418
if !isWorkflow && len(template.Workflows) > 0 {
419
continue
420
}
421
}
422
if isWorkflow {
423
if !areWorkflowTemplatesValid(store, template.Workflows) {
424
areTemplatesValid = false
425
continue
426
}
427
}
428
}
429
return areTemplatesValid
430
}
431
432
func areWorkflowTemplatesValid(store *Store, workflows []*workflows.WorkflowTemplate) bool {
433
for _, workflow := range workflows {
434
if !areWorkflowTemplatesValid(store, workflow.Subtemplates) {
435
return false
436
}
437
_, err := store.config.Catalog.GetTemplatePath(workflow.Template)
438
if err != nil {
439
if isParsingError(store, "Error occurred loading template %s: %s\n", workflow.Template, err) {
440
return false
441
}
442
}
443
}
444
return true
445
}
446
447
func isParsingError(store *Store, message string, template string, err error) bool {
448
if errors.Is(err, templates.ErrExcluded) {
449
return false
450
}
451
if errors.Is(err, templates.ErrCreateTemplateExecutor) {
452
return false
453
}
454
store.logger.Error().Msgf(message, template, err)
455
return true
456
}
457
458
// LoadTemplates takes a list of templates and returns paths for them
459
func (store *Store) LoadTemplates(templatesList []string) []*templates.Template {
460
return store.LoadTemplatesWithTags(templatesList, nil)
461
}
462
463
// LoadWorkflows takes a list of workflows and returns paths for them
464
func (store *Store) LoadWorkflows(workflowsList []string) []*templates.Template {
465
includedWorkflows, errs := store.config.Catalog.GetTemplatesPath(workflowsList)
466
store.logErroredTemplates(errs)
467
workflowPathMap := store.pathFilter.Match(includedWorkflows)
468
469
loadedWorkflows := make([]*templates.Template, 0, len(workflowPathMap))
470
for workflowPath := range workflowPathMap {
471
loaded, err := store.config.ExecutorOptions.Parser.LoadWorkflow(workflowPath, store.config.Catalog)
472
if err != nil {
473
store.logger.Warning().Msgf("Could not load workflow %s: %s\n", workflowPath, err)
474
}
475
if loaded {
476
parsed, err := templates.Parse(workflowPath, store.preprocessor, store.config.ExecutorOptions)
477
if err != nil {
478
store.logger.Warning().Msgf("Could not parse workflow %s: %s\n", workflowPath, err)
479
} else if parsed != nil {
480
loadedWorkflows = append(loadedWorkflows, parsed)
481
}
482
}
483
}
484
return loadedWorkflows
485
}
486
487
// LoadTemplatesWithTags takes a list of templates and extra tags
488
// returning templates that match.
489
func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templates.Template {
490
includedTemplates, errs := store.config.Catalog.GetTemplatesPath(templatesList)
491
store.logErroredTemplates(errs)
492
templatePathMap := store.pathFilter.Match(includedTemplates)
493
494
loadedTemplates := sliceutil.NewSyncSlice[*templates.Template]()
495
496
loadTemplate := func(tmpl *templates.Template) {
497
loadedTemplates.Append(tmpl)
498
// increment signed/unsigned counters
499
if tmpl.Verified {
500
if tmpl.TemplateVerifier == "" {
501
templates.SignatureStats[keys.PDVerifier].Add(1)
502
} else {
503
templates.SignatureStats[tmpl.TemplateVerifier].Add(1)
504
}
505
} else {
506
templates.SignatureStats[templates.Unsigned].Add(1)
507
}
508
}
509
510
wgLoadTemplates, errWg := syncutil.New(syncutil.WithSize(50))
511
if errWg != nil {
512
panic("could not create wait group")
513
}
514
515
if store.config.ExecutorOptions.Options.ExecutionId == "" {
516
store.config.ExecutorOptions.Options.ExecutionId = xid.New().String()
517
}
518
519
dialers := protocolstate.GetDialersWithId(store.config.ExecutorOptions.Options.ExecutionId)
520
if dialers == nil {
521
panic("dialers with executionId " + store.config.ExecutorOptions.Options.ExecutionId + " not found")
522
}
523
524
for templatePath := range templatePathMap {
525
wgLoadTemplates.Add()
526
go func(templatePath string) {
527
defer wgLoadTemplates.Done()
528
529
loaded, err := store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, tags, store.config.Catalog)
530
if loaded || store.pathFilter.MatchIncluded(templatePath) {
531
parsed, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
532
if err != nil {
533
// exclude templates not compatible with offline matching from total runtime warning stats
534
if !errors.Is(err, templates.ErrIncompatibleWithOfflineMatching) {
535
stats.Increment(templates.RuntimeWarningsStats)
536
}
537
store.logger.Warning().Msgf("Could not parse template %s: %s\n", templatePath, err)
538
} else if parsed != nil {
539
if !parsed.Verified && store.config.ExecutorOptions.Options.DisableUnsignedTemplates {
540
// skip unverified templates when prompted to
541
stats.Increment(templates.SkippedUnsignedStats)
542
return
543
}
544
545
if parsed.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
546
stats.Increment(templates.ExcludedSelfContainedStats)
547
return
548
}
549
550
if parsed.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
551
stats.Increment(templates.ExcludedFileStats)
552
return
553
}
554
555
// if template has request signature like aws then only signed and verified templates are allowed
556
if parsed.UsesRequestSignature() && !parsed.Verified {
557
stats.Increment(templates.SkippedRequestSignatureStats)
558
return
559
}
560
// DAST only templates
561
// Skip DAST filter when loading auth templates
562
if store.ID() != AuthStoreId && store.config.ExecutorOptions.Options.DAST {
563
// check if the template is a DAST template
564
// also allow global matchers template to be loaded
565
if parsed.IsFuzzing() || parsed.Options.GlobalMatchers != nil && parsed.Options.GlobalMatchers.HasMatchers() {
566
loadTemplate(parsed)
567
}
568
} else if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
569
// donot include headless template in final list if headless flag is not set
570
stats.Increment(templates.ExcludedHeadlessTmplStats)
571
if config.DefaultConfig.LogAllEvents {
572
store.logger.Print().Msgf("[%v] Headless flag is required for headless template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
573
}
574
} else if len(parsed.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
575
// donot include 'Code' protocol custom template in final list if code flag is not set
576
stats.Increment(templates.ExcludedCodeTmplStats)
577
if config.DefaultConfig.LogAllEvents {
578
store.logger.Print().Msgf("[%v] Code flag is required for code protocol template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
579
}
580
} else if len(parsed.RequestsCode) > 0 && !parsed.Verified && len(parsed.Workflows) == 0 {
581
// donot include unverified 'Code' protocol custom template in final list
582
stats.Increment(templates.SkippedCodeTmplTamperedStats)
583
// these will be skipped so increment skip counter
584
stats.Increment(templates.SkippedUnsignedStats)
585
if config.DefaultConfig.LogAllEvents {
586
store.logger.Print().Msgf("[%v] Tampered/Unsigned template at %v.\n", aurora.Yellow("WRN").String(), templatePath)
587
}
588
} else if parsed.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
589
stats.Increment(templates.ExludedDastTmplStats)
590
if config.DefaultConfig.LogAllEvents {
591
store.logger.Print().Msgf("[%v] -dast flag is required for DAST template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
592
}
593
} else {
594
loadTemplate(parsed)
595
}
596
}
597
}
598
if err != nil {
599
if strings.Contains(err.Error(), templates.ErrExcluded.Error()) {
600
stats.Increment(templates.TemplatesExcludedStats)
601
if config.DefaultConfig.LogAllEvents {
602
store.logger.Print().Msgf("[%v] %v\n", aurora.Yellow("WRN").String(), err.Error())
603
}
604
return
605
}
606
store.logger.Warning().Msg(err.Error())
607
}
608
}(templatePath)
609
}
610
611
wgLoadTemplates.Wait()
612
613
sort.SliceStable(loadedTemplates.Slice, func(i, j int) bool {
614
return loadedTemplates.Slice[i].Path < loadedTemplates.Slice[j].Path
615
})
616
617
return loadedTemplates.Slice
618
}
619
620
// IsHTTPBasedProtocolUsed returns true if http/headless protocol is being used for
621
// any templates.
622
func IsHTTPBasedProtocolUsed(store *Store) bool {
623
templates := append(store.Templates(), store.Workflows()...)
624
625
for _, template := range templates {
626
if len(template.RequestsHTTP) > 0 || len(template.RequestsHeadless) > 0 {
627
return true
628
}
629
if len(template.Workflows) > 0 {
630
if workflowContainsProtocol(template.Workflows) {
631
return true
632
}
633
}
634
}
635
return false
636
}
637
638
func workflowContainsProtocol(workflow []*workflows.WorkflowTemplate) bool {
639
for _, workflow := range workflow {
640
for _, template := range workflow.Matchers {
641
if workflowContainsProtocol(template.Subtemplates) {
642
return true
643
}
644
}
645
for _, template := range workflow.Subtemplates {
646
if workflowContainsProtocol(template.Subtemplates) {
647
return true
648
}
649
}
650
for _, executer := range workflow.Executers {
651
if executer.TemplateType == templateTypes.HTTPProtocol || executer.TemplateType == templateTypes.HeadlessProtocol {
652
return true
653
}
654
}
655
}
656
return false
657
}
658
659
func (s *Store) logErroredTemplates(erred map[string]error) {
660
for template, err := range erred {
661
if s.NotFoundCallback == nil || !s.NotFoundCallback(template) {
662
s.logger.Error().Msgf("Could not find template '%s': %s", template, err)
663
}
664
}
665
}
666
667