Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/templates/templates.go
2848 views
1
//go:generate dstdocgen -path "" -structure Template -output templates_doc.go -package templates
2
package templates
3
4
import (
5
"io"
6
"path/filepath"
7
"strconv"
8
"strings"
9
10
"github.com/projectdiscovery/nuclei/v3/pkg/model"
11
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
12
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/code"
13
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/variables"
14
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/dns"
15
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/file"
16
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless"
17
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http"
18
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/javascript"
19
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network"
20
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/ssl"
21
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/websocket"
22
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/whois"
23
"github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
24
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
25
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
26
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
27
"github.com/projectdiscovery/utils/errkit"
28
fileutil "github.com/projectdiscovery/utils/file"
29
"go.uber.org/multierr"
30
"gopkg.in/yaml.v2"
31
)
32
33
// Template is a YAML input file which defines all the requests and
34
// other metadata for a template.
35
type Template struct {
36
// description: |
37
// ID is the unique id for the template.
38
//
39
// #### Good IDs
40
//
41
// A good ID uniquely identifies what the requests in the template
42
// are doing. Let's say you have a template that identifies a git-config
43
// file on the webservers, a good name would be `git-config-exposure`. Another
44
// example name is `azure-apps-nxdomain-takeover`.
45
// examples:
46
// - name: ID Example
47
// value: "\"CVE-2021-19520\""
48
ID string `yaml:"id" json:"id" jsonschema:"title=id of the template,description=The Unique ID for the template,required,example=cve-2021-19520,pattern=^([a-zA-Z0-9]+[-_])*[a-zA-Z0-9]+$"`
49
// description: |
50
// Info contains metadata information about the template.
51
// examples:
52
// - value: exampleInfoStructure
53
Info model.Info `yaml:"info" json:"info" jsonschema:"title=info for the template,description=Info contains metadata for the template,required,type=object"`
54
// description: |
55
// Flow contains the execution flow for the template.
56
// examples:
57
// - flow: |
58
// for region in regions {
59
// http(0)
60
// }
61
// for vpc in vpcs {
62
// http(1)
63
// }
64
//
65
Flow string `yaml:"flow,omitempty" json:"flow,omitempty" jsonschema:"title=template execution flow in js,description=Flow contains js code which defines how the template should be executed,type=string,example='flow: http(0) && http(1)'"`
66
// description: |
67
// Requests contains the http request to make in the template.
68
// WARNING: 'requests' will be deprecated and will be removed in a future release. Please use 'http' instead.
69
// examples:
70
// - value: exampleNormalHTTPRequest
71
RequestsHTTP []*http.Request `yaml:"requests,omitempty" json:"requests,omitempty" jsonschema:"title=http requests to make,description=HTTP requests to make for the template,deprecated=true"`
72
// description: |
73
// HTTP contains the http request to make in the template.
74
// examples:
75
// - value: exampleNormalHTTPRequest
76
// RequestsWithHTTP is placeholder(internal) only, and should not be used instead use RequestsHTTP
77
// Deprecated: Use RequestsHTTP instead.
78
RequestsWithHTTP []*http.Request `yaml:"http,omitempty" json:"http,omitempty" jsonschema:"title=http requests to make,description=HTTP requests to make for the template"`
79
// description: |
80
// DNS contains the dns request to make in the template
81
// examples:
82
// - value: exampleNormalDNSRequest
83
RequestsDNS []*dns.Request `yaml:"dns,omitempty" json:"dns,omitempty" jsonschema:"title=dns requests to make,description=DNS requests to make for the template"`
84
// description: |
85
// File contains the file request to make in the template
86
// examples:
87
// - value: exampleNormalFileRequest
88
RequestsFile []*file.Request `yaml:"file,omitempty" json:"file,omitempty" jsonschema:"title=file requests to make,description=File requests to make for the template"`
89
// description: |
90
// Network contains the network request to make in the template
91
// WARNING: 'network' will be deprecated and will be removed in a future release. Please use 'tcp' instead.
92
// examples:
93
// - value: exampleNormalNetworkRequest
94
RequestsNetwork []*network.Request `yaml:"network,omitempty" json:"network,omitempty" jsonschema:"title=network requests to make,description=Network requests to make for the template,deprecated=true"`
95
// description: |
96
// TCP contains the network request to make in the template
97
// examples:
98
// - value: exampleNormalNetworkRequest
99
// RequestsWithTCP is placeholder(internal) only, and should not be used instead use RequestsNetwork
100
// Deprecated: Use RequestsNetwork instead.
101
RequestsWithTCP []*network.Request `yaml:"tcp,omitempty" json:"tcp,omitempty" jsonschema:"title=network(tcp) requests to make,description=Network requests to make for the template"`
102
// description: |
103
// Headless contains the headless request to make in the template.
104
RequestsHeadless []*headless.Request `yaml:"headless,omitempty" json:"headless,omitempty" jsonschema:"title=headless requests to make,description=Headless requests to make for the template"`
105
// description: |
106
// SSL contains the SSL request to make in the template.
107
RequestsSSL []*ssl.Request `yaml:"ssl,omitempty" json:"ssl,omitempty" jsonschema:"title=ssl requests to make,description=SSL requests to make for the template"`
108
// description: |
109
// Websocket contains the Websocket request to make in the template.
110
RequestsWebsocket []*websocket.Request `yaml:"websocket,omitempty" json:"websocket,omitempty" jsonschema:"title=websocket requests to make,description=Websocket requests to make for the template"`
111
// description: |
112
// WHOIS contains the WHOIS request to make in the template.
113
RequestsWHOIS []*whois.Request `yaml:"whois,omitempty" json:"whois,omitempty" jsonschema:"title=whois requests to make,description=WHOIS requests to make for the template"`
114
// description: |
115
// Code contains code snippets.
116
RequestsCode []*code.Request `yaml:"code,omitempty" json:"code,omitempty" jsonschema:"title=code snippets to make,description=Code snippets"`
117
// description: |
118
// Javascript contains the javascript request to make in the template.
119
RequestsJavascript []*javascript.Request `yaml:"javascript,omitempty" json:"javascript,omitempty" jsonschema:"title=javascript requests to make,description=Javascript requests to make for the template"`
120
121
// description: |
122
// Workflows is a yaml based workflow declaration code.
123
workflows.Workflow `yaml:",inline,omitempty" jsonschema:"title=workflows to run,description=Workflows to run for the template"`
124
CompiledWorkflow *workflows.Workflow `yaml:"-" json:"-" jsonschema:"-"`
125
126
// description: |
127
// Self Contained marks Requests for the template as self-contained
128
SelfContained bool `yaml:"self-contained,omitempty" json:"self-contained,omitempty" jsonschema:"title=mark requests as self-contained,description=Mark Requests for the template as self-contained"`
129
// description: |
130
// Stop execution once first match is found
131
StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" json:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop at first match for the template"`
132
133
// description: |
134
// Signature is the request signature method
135
// WARNING: 'signature' will be deprecated and will be removed in a future release. Prefer using 'code' protocol for writing cloud checks
136
// values:
137
// - "AWS"
138
Signature http.SignatureTypeHolder `yaml:"signature,omitempty" json:"signature,omitempty" jsonschema:"title=signature is the http request signature method,description=Signature is the HTTP Request signature Method,enum=AWS,deprecated=true"`
139
140
// description: |
141
// Variables contains any variables for the current request.
142
Variables variables.Variable `yaml:"variables,omitempty" json:"variables,omitempty" jsonschema:"title=variables for the http request,description=Variables contains any variables for the current request,type=object"`
143
144
// description: |
145
// Constants contains any scalar constant for the current template
146
Constants map[string]interface{} `yaml:"constants,omitempty" json:"constants,omitempty" jsonschema:"title=constant for the template,description=constants contains any constant for the template,type=object"`
147
148
// TotalRequests is the total number of requests for the template.
149
TotalRequests int `yaml:"-" json:"-"`
150
// Executer is the actual template executor for running template requests
151
Executer protocols.Executer `yaml:"-" json:"-"`
152
153
Path string `yaml:"-" json:"-"`
154
155
// Verified defines if the template signature is digitally verified
156
Verified bool `yaml:"-" json:"-"`
157
// TemplateVerifier is identifier verifier used to verify the template (default nuclei-templates have projectdiscovery/nuclei-templates)
158
TemplateVerifier string `yaml:"-" json:"-"`
159
// RequestsQueue contains all template requests in order (both protocol & request order)
160
RequestsQueue []protocols.Request `yaml:"-" json:"-"`
161
162
// ImportedFiles contains list of files whose contents are imported after template was compiled
163
ImportedFiles []string `yaml:"-" json:"-"`
164
}
165
166
// HasCodeProtocol returns true if the template has a code protocol section
167
//
168
// Deprecated: Use [HasCodeRequest] instead.
169
func (template *Template) HasCodeProtocol() bool {
170
return len(template.RequestsCode) > 0
171
}
172
173
// HasFileProtocol returns true if the template has a file protocol section.
174
//
175
// Deprecated: Use [HasFileRequest] instead.
176
func (template *Template) HasFileProtocol() bool {
177
return len(template.RequestsFile) > 0
178
}
179
180
// Type returns the type of the template
181
func (template *Template) Type() types.ProtocolType {
182
switch {
183
case template.HasDNSRequest():
184
return types.DNSProtocol
185
case template.HasFileRequest():
186
return types.FileProtocol
187
case template.HasHTTPRequest():
188
return types.HTTPProtocol
189
case template.HasHeadlessRequest():
190
return types.HeadlessProtocol
191
case template.HasNetworkRequest():
192
return types.NetworkProtocol
193
case template.HasSSLRequest():
194
return types.SSLProtocol
195
case template.HasWebsocketRequest():
196
return types.WebsocketProtocol
197
case template.HasWHOISRequest():
198
return types.WHOISProtocol
199
case template.HasCodeRequest():
200
return types.CodeProtocol
201
case template.HasJavascriptRequest():
202
return types.JavascriptProtocol
203
case template.HasWorkflows():
204
return types.WorkflowProtocol
205
default:
206
return types.InvalidProtocol
207
}
208
}
209
210
// IsFuzzing returns true if the template is a fuzzing template
211
//
212
// Deprecated: Use [IsFuzzableRequest] instead.
213
func (template *Template) IsFuzzing() bool {
214
if len(template.RequestsHTTP) == 0 && len(template.RequestsHeadless) == 0 {
215
// fuzzing is only supported for http and headless protocols
216
return false
217
}
218
if len(template.RequestsHTTP) > 0 {
219
for _, request := range template.RequestsHTTP {
220
if len(request.Fuzzing) > 0 {
221
return true
222
}
223
}
224
}
225
if len(template.RequestsHeadless) > 0 {
226
for _, request := range template.RequestsHeadless {
227
if len(request.Fuzzing) > 0 {
228
return true
229
}
230
}
231
}
232
return false
233
}
234
235
// UsesRequestSignature returns true if the template uses a request signature like AWS
236
func (template *Template) UsesRequestSignature() bool {
237
return template.Signature.Value.String() != ""
238
}
239
240
// validateAllRequestIDs check if that protocol already has given id if not
241
// then is is manually set to proto_index
242
func (template *Template) validateAllRequestIDs() {
243
// this is required in multiprotocol and flow where we save response variables
244
// and all other data in template context if template as two requests in a protocol
245
// then it is overwritten to avoid this we use proto_index as request ID
246
if template.HasCodeRequest(1) {
247
for i, req := range template.RequestsCode {
248
if req.ID == "" {
249
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
250
}
251
}
252
}
253
254
if template.HasDNSRequest(1) {
255
for i, req := range template.RequestsDNS {
256
if req.ID == "" {
257
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
258
}
259
}
260
}
261
262
if template.HasFileRequest(1) {
263
for i, req := range template.RequestsFile {
264
if req.ID == "" {
265
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
266
}
267
}
268
}
269
270
if template.HasHTTPRequest(1) {
271
for i, req := range template.RequestsHTTP {
272
if req.ID == "" {
273
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
274
}
275
}
276
}
277
278
if template.HasHeadlessRequest(1) {
279
for i, req := range template.RequestsHeadless {
280
if req.ID == "" {
281
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
282
}
283
}
284
}
285
286
if template.HasNetworkRequest(1) {
287
for i, req := range template.RequestsNetwork {
288
if req.ID == "" {
289
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
290
}
291
}
292
}
293
294
if template.HasSSLRequest(1) {
295
for i, req := range template.RequestsSSL {
296
if req.ID == "" {
297
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
298
}
299
}
300
}
301
302
if template.HasWebsocketRequest(1) {
303
for i, req := range template.RequestsWebsocket {
304
if req.ID == "" {
305
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
306
}
307
}
308
}
309
310
if template.HasWHOISRequest(1) {
311
for i, req := range template.RequestsWHOIS {
312
if req.ID == "" {
313
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
314
}
315
}
316
}
317
318
if template.HasJavascriptRequest(1) {
319
for i, req := range template.RequestsJavascript {
320
if req.ID == "" {
321
req.ID = req.Type().String() + "_" + strconv.Itoa(i+1)
322
}
323
}
324
}
325
}
326
327
// MarshalYAML forces recursive struct validation during marshal operation
328
func (template *Template) MarshalYAML() ([]byte, error) {
329
out, marshalErr := yaml.Marshal(template)
330
// Use shared validator to avoid rebuilding struct cache for every template marshal
331
errValidate := tplValidator.Struct(template)
332
return out, multierr.Append(marshalErr, errValidate)
333
}
334
335
// UnmarshalYAML forces recursive struct validation after unmarshal operation
336
func (template *Template) UnmarshalYAML(unmarshal func(interface{}) error) error {
337
type Alias Template
338
alias := &Alias{}
339
err := unmarshal(alias)
340
if err != nil {
341
return err
342
}
343
*template = Template(*alias)
344
345
if !ReTemplateID.MatchString(template.ID) {
346
return errkit.New("template id must match expression %v", ReTemplateID, "tag", "invalid_template")
347
}
348
349
info := template.Info
350
if utils.IsBlank(info.Name) {
351
return errkit.New("no template name field provided", "tag", "invalid_template")
352
}
353
354
if info.Authors.IsEmpty() {
355
return errkit.New("no template author field provided", "tag", "invalid_template")
356
}
357
358
if template.HasHTTPRequest() || template.HasNetworkRequest() {
359
_ = deprecatedProtocolNameTemplates.Set(template.ID, true)
360
}
361
362
if HasRequest(alias.RequestsHTTP) && HasRequest(alias.RequestsWithHTTP) {
363
return errkit.New("use http or requests, both are not supported", "tag", "invalid_template")
364
}
365
366
if HasRequest(alias.RequestsNetwork) && HasRequest(alias.RequestsWithTCP) {
367
return errkit.New("use tcp or network, both are not supported", "tag", "invalid_template")
368
}
369
370
if HasRequest(alias.RequestsWithHTTP) {
371
template.RequestsHTTP = alias.RequestsWithHTTP
372
}
373
374
if HasRequest(alias.RequestsWithTCP) {
375
template.RequestsNetwork = alias.RequestsWithTCP
376
}
377
378
err = tplValidator.Struct(template)
379
if err != nil {
380
return err
381
}
382
383
// check if the template contains more than 1 protocol request
384
// if so preserve the order of the protocols and requests
385
if template.hasMultipleRequests() {
386
var tempmap yaml.MapSlice
387
388
err = unmarshal(&tempmap)
389
if err != nil {
390
return errkit.Wrapf(err, "failed to unmarshal multi protocol template %s", template.ID)
391
}
392
393
arr := []string{}
394
for _, v := range tempmap {
395
key, ok := v.Key.(string)
396
if !ok {
397
continue
398
}
399
400
arr = append(arr, key)
401
}
402
403
// add protocols to the protocol stack (the idea is to preserve the order of the protocols)
404
template.addRequestsToQueue(arr...)
405
}
406
407
return nil
408
}
409
410
// ImportFileRefs checks if sensitive fields like `flow` , `source` in code protocol are referencing files
411
// instead of actual javascript / engine code if so it loads the file contents and replaces the reference
412
func (template *Template) ImportFileRefs(options *protocols.ExecutorOptions) error {
413
var errs []error
414
415
loadFile := func(source string) (string, bool) {
416
// load file respecting sandbox
417
data, err := options.Options.LoadHelperFile(source, options.TemplatePath, options.Catalog)
418
if err == nil {
419
defer func() {
420
_ = data.Close()
421
}()
422
423
bin, err := io.ReadAll(data)
424
if err == nil {
425
return string(bin), true
426
} else {
427
errs = append(errs, err)
428
}
429
} else {
430
errs = append(errs, err)
431
}
432
433
return "", false
434
}
435
436
// for code protocol requests
437
for _, request := range template.RequestsCode {
438
// simple test to check if source is a file or a snippet
439
if !strings.ContainsRune(request.Source, '\n') && fileutil.FileExists(request.Source) {
440
if val, ok := loadFile(request.Source); ok {
441
template.ImportedFiles = append(template.ImportedFiles, request.Source)
442
request.Source = val
443
}
444
}
445
}
446
447
// for javascript protocol code references
448
for _, request := range template.RequestsJavascript {
449
// simple test to check if source is a file or a snippet
450
if !strings.ContainsRune(request.Code, '\n') && fileutil.FileExists(request.Code) {
451
if val, ok := loadFile(request.Code); ok {
452
template.ImportedFiles = append(template.ImportedFiles, request.Code)
453
request.Code = val
454
}
455
}
456
}
457
458
// flow code references
459
if template.IsFlowTemplate() {
460
if filepath.Ext(template.Flow) == ".js" && fileutil.FileExists(template.Flow) {
461
if val, ok := loadFile(template.Flow); ok {
462
template.ImportedFiles = append(template.ImportedFiles, template.Flow)
463
template.Flow = val
464
}
465
}
466
467
options.Flow = template.Flow
468
}
469
470
// for multiprotocol requests
471
// mutually exclusive with flow
472
if HasRequest(template.RequestsQueue) && template.Flow == "" {
473
// this is most likely a multiprotocol template
474
for _, req := range template.RequestsQueue {
475
if req.Type() == types.CodeProtocol {
476
request := req.(*code.Request)
477
// simple test to check if source is a file or a snippet
478
if !strings.ContainsRune(request.Source, '\n') && fileutil.FileExists(request.Source) {
479
if val, ok := loadFile(request.Source); ok {
480
template.ImportedFiles = append(template.ImportedFiles, request.Source)
481
request.Source = val
482
}
483
}
484
}
485
}
486
487
// for javascript protocol code references
488
for _, req := range template.RequestsQueue {
489
if req.Type() == types.JavascriptProtocol {
490
request := req.(*javascript.Request)
491
// simple test to check if source is a file or a snippet
492
if !strings.ContainsRune(request.Code, '\n') && fileutil.FileExists(request.Code) {
493
if val, ok := loadFile(request.Code); ok {
494
template.ImportedFiles = append(template.ImportedFiles, request.Code)
495
request.Code = val
496
}
497
}
498
}
499
}
500
}
501
502
return multierr.Combine(errs...)
503
}
504
505
// GetFileImports returns a list of files that are imported by the template
506
func (template *Template) GetFileImports() []string {
507
return template.ImportedFiles
508
}
509
510
// addRequestsToQueue adds protocol requests to the queue and preserves order of the protocols and requests
511
func (template *Template) addRequestsToQueue(keys ...string) {
512
for _, key := range keys {
513
switch key {
514
case types.DNSProtocol.String():
515
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsDNS)...)
516
case types.FileProtocol.String():
517
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsFile)...)
518
case types.HTTPProtocol.String():
519
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsHTTP)...)
520
case types.HeadlessProtocol.String():
521
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsHeadless)...)
522
case types.NetworkProtocol.String():
523
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsNetwork)...)
524
case types.SSLProtocol.String():
525
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsSSL)...)
526
case types.WebsocketProtocol.String():
527
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsWebsocket)...)
528
case types.WHOISProtocol.String():
529
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsWHOIS)...)
530
case types.CodeProtocol.String():
531
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsCode)...)
532
case types.JavascriptProtocol.String():
533
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsJavascript)...)
534
// for deprecated protocols
535
case "requests":
536
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsHTTP)...)
537
case "network":
538
template.RequestsQueue = append(template.RequestsQueue, template.convertRequestToProtocolsRequest(template.RequestsNetwork)...)
539
}
540
}
541
}
542
543
// hasMultipleRequests checks if the template has multiple requests
544
// if so it preserves the order of the request during compile and execution
545
func (template *Template) hasMultipleRequests() bool {
546
counter := len(template.RequestsDNS) + len(template.RequestsFile) +
547
len(template.RequestsHTTP) + len(template.RequestsHeadless) +
548
len(template.RequestsNetwork) + len(template.RequestsSSL) +
549
len(template.RequestsWebsocket) + len(template.RequestsWHOIS) +
550
len(template.RequestsCode) + len(template.RequestsJavascript)
551
return counter > 1
552
}
553
554
// MarshalJSON forces recursive struct validation during marshal operation
555
func (template *Template) MarshalJSON() ([]byte, error) {
556
type TemplateAlias Template //avoid recursion
557
out, marshalErr := json.Marshal((*TemplateAlias)(template))
558
errValidate := tplValidator.Struct(template)
559
return out, multierr.Append(marshalErr, errValidate)
560
}
561
562
// UnmarshalJSON forces recursive struct validation after unmarshal operation
563
func (template *Template) UnmarshalJSON(data []byte) error {
564
type Alias Template
565
alias := &Alias{}
566
err := json.Unmarshal(data, alias)
567
if err != nil {
568
return err
569
}
570
*template = Template(*alias)
571
err = tplValidator.Struct(template)
572
if err != nil {
573
return err
574
}
575
// check if the template contains more than 1 protocol request
576
// if so preserve the order of the protocols and requests
577
if template.hasMultipleRequests() {
578
var tempMap map[string]interface{}
579
err = json.Unmarshal(data, &tempMap)
580
if err != nil {
581
return errkit.Wrapf(err, "failed to unmarshal multi protocol template %s", template.ID)
582
}
583
arr := []string{}
584
for k := range tempMap {
585
arr = append(arr, k)
586
}
587
template.addRequestsToQueue(arr...)
588
}
589
return nil
590
}
591
592
// Requirements holds the required options for a template to be enabled.
593
type Requirements struct {
594
Headless bool
595
Code bool
596
DAST bool
597
SelfContained bool
598
File bool
599
}
600
601
// Requirements returns what options must be enabled for the template to run.
602
func (template *Template) Requirements() Requirements {
603
return Requirements{
604
Headless: template.HasHeadlessRequest(),
605
Code: template.HasCodeRequest(),
606
DAST: template.IsFuzzableRequest(),
607
SelfContained: template.SelfContained,
608
File: template.HasFileRequest(),
609
}
610
}
611
612
// Capabilities represents the enabled options/capabilities.
613
type Capabilities struct {
614
Headless bool
615
Code bool
616
DAST bool
617
SelfContained bool
618
File bool
619
}
620
621
// IsEnabledFor checks if all template requirements are satisfied by the given
622
// capabilities.
623
func (template *Template) IsEnabledFor(caps Capabilities) bool {
624
reqs := template.Requirements()
625
626
if reqs.Headless && !caps.Headless {
627
return false
628
}
629
630
if reqs.Code && !caps.Code {
631
return false
632
}
633
634
if reqs.DAST && !caps.DAST {
635
return false
636
}
637
638
if reqs.SelfContained && !caps.SelfContained {
639
return false
640
}
641
642
if reqs.File && !caps.File {
643
return false
644
}
645
646
return true
647
}
648
649