2021-08-03 22:33:50 +05:30
//go:generate dstdocgen -path "" -structure Template -output templates_doc.go -package templates
2020-04-04 00:17:57 +05:30
package templates
import (
2023-10-13 13:17:27 +05:30
"io"
"path/filepath"
2023-08-31 18:03:01 +05:30
"strconv"
2023-10-13 13:17:27 +05:30
"strings"
2021-12-16 11:09:38 +01:00
2023-10-17 17:44:13 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/model"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/code"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/variables"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/dns"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/file"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/javascript"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/ssl"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/websocket"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/whois"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
2024-06-16 04:27:31 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
2025-02-11 04:31:37 +07:00
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
2023-10-17 17:44:13 +05:30
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
2025-08-20 05:28:23 +05:30
"github.com/projectdiscovery/utils/errkit"
2023-10-13 13:17:27 +05:30
fileutil "github.com/projectdiscovery/utils/file"
2021-12-16 11:09:38 +01:00
"go.uber.org/multierr"
"gopkg.in/yaml.v2"
2020-04-04 00:17:57 +05:30
)
2021-08-04 14:20:48 +05:30
// Template is a YAML input file which defines all the requests and
// other metadata for a template.
2020-04-04 00:17:57 +05:30
type Template struct {
2021-07-27 16:03:56 +05:30
// description: |
2021-09-01 15:48:01 +05:30
// ID is the unique id for the template.
2021-07-27 16:03:56 +05:30
//
// #### Good IDs
//
2021-08-03 20:36:26 +05:30
// A good ID uniquely identifies what the requests in the template
2021-07-27 16:03:56 +05:30
// are doing. Let's say you have a template that identifies a git-config
// file on the webservers, a good name would be `git-config-exposure`. Another
// example name is `azure-apps-nxdomain-takeover`.
// examples:
// - name: ID Example
2021-09-01 15:53:30 +05:30
// value: "\"CVE-2021-19520\""
2024-03-27 23:52:08 +05:30
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]+$" `
2021-07-27 16:03:56 +05:30
// description: |
2021-08-19 16:51:02 +05:30
// Info contains metadata information about the template.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleInfoStructure
2024-03-27 23:52:08 +05:30
Info model . Info ` yaml:"info" json:"info" jsonschema:"title=info for the template,description=Info contains metadata for the template,required,type=object" `
2021-07-27 16:03:56 +05:30
// description: |
2023-08-31 18:03:01 +05:30
// Flow contains the execution flow for the template.
// examples:
// - flow: |
// for region in regions {
// http(0)
// }
// for vpc in vpcs {
// http(1)
// }
//
2024-03-27 23:52:08 +05:30
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)'" `
2023-08-31 18:03:01 +05:30
// description: |
2021-08-04 14:20:48 +05:30
// Requests contains the http request to make in the template.
2023-03-21 00:48:35 +05:30
// WARNING: 'requests' will be deprecated and will be removed in a future release. Please use 'http' instead.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalHTTPRequest
2024-03-27 23:52:08 +05:30
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" `
2021-07-27 16:03:56 +05:30
// description: |
2023-03-21 00:48:35 +05:30
// HTTP contains the http request to make in the template.
// examples:
// - value: exampleNormalHTTPRequest
// RequestsWithHTTP is placeholder(internal) only, and should not be used instead use RequestsHTTP
2023-06-09 19:52:56 +05:30
// Deprecated: Use RequestsHTTP instead.
2023-03-21 00:48:35 +05:30
RequestsWithHTTP [ ] * http . Request ` yaml:"http,omitempty" json:"http,omitempty" jsonschema:"title=http requests to make,description=HTTP requests to make for the template" `
// description: |
2021-07-27 16:03:56 +05:30
// DNS contains the dns request to make in the template
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalDNSRequest
2021-08-23 23:50:45 +05:30
RequestsDNS [ ] * dns . Request ` yaml:"dns,omitempty" json:"dns,omitempty" jsonschema:"title=dns requests to make,description=DNS requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
// File contains the file request to make in the template
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalFileRequest
2021-08-23 23:50:45 +05:30
RequestsFile [ ] * file . Request ` yaml:"file,omitempty" json:"file,omitempty" jsonschema:"title=file requests to make,description=File requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
// Network contains the network request to make in the template
2023-03-21 00:48:35 +05:30
// WARNING: 'network' will be deprecated and will be removed in a future release. Please use 'tcp' instead.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalNetworkRequest
2024-03-27 23:52:08 +05:30
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" `
2021-07-27 16:03:56 +05:30
// description: |
2023-03-21 00:48:35 +05:30
// TCP contains the network request to make in the template
// examples:
// - value: exampleNormalNetworkRequest
// RequestsWithTCP is placeholder(internal) only, and should not be used instead use RequestsNetwork
2023-06-09 19:52:56 +05:30
// Deprecated: Use RequestsNetwork instead.
2023-03-21 00:48:35 +05:30
RequestsWithTCP [ ] * network . Request ` yaml:"tcp,omitempty" json:"tcp,omitempty" jsonschema:"title=network(tcp) requests to make,description=Network requests to make for the template" `
// description: |
2021-07-27 16:03:56 +05:30
// Headless contains the headless request to make in the template.
2021-08-23 23:50:45 +05:30
RequestsHeadless [ ] * headless . Request ` yaml:"headless,omitempty" json:"headless,omitempty" jsonschema:"title=headless requests to make,description=Headless requests to make for the template" `
2021-09-22 22:41:07 +05:30
// description: |
// SSL contains the SSL request to make in the template.
RequestsSSL [ ] * ssl . Request ` yaml:"ssl,omitempty" json:"ssl,omitempty" jsonschema:"title=ssl requests to make,description=SSL requests to make for the template" `
2021-09-27 18:02:49 +05:30
// description: |
// Websocket contains the Websocket request to make in the template.
RequestsWebsocket [ ] * websocket . Request ` yaml:"websocket,omitempty" json:"websocket,omitempty" jsonschema:"title=websocket requests to make,description=Websocket requests to make for the template" `
2021-12-16 17:08:02 +05:30
// description: |
// WHOIS contains the WHOIS request to make in the template.
RequestsWHOIS [ ] * whois . Request ` yaml:"whois,omitempty" json:"whois,omitempty" jsonschema:"title=whois requests to make,description=WHOIS requests to make for the template" `
2023-06-09 17:24:24 +02:00
// description: |
// Code contains code snippets.
RequestsCode [ ] * code . Request ` yaml:"code,omitempty" json:"code,omitempty" jsonschema:"title=code snippets to make,description=Code snippets" `
2023-09-16 16:02:17 +05:30
// description: |
// Javascript contains the javascript request to make in the template.
RequestsJavascript [ ] * javascript . Request ` yaml:"javascript,omitempty" json:"javascript,omitempty" jsonschema:"title=javascript requests to make,description=Javascript requests to make for the template" `
2023-06-09 17:24:24 +02:00
2021-07-27 16:03:56 +05:30
// description: |
// Workflows is a yaml based workflow declaration code.
2021-08-23 23:50:45 +05:30
workflows . Workflow ` yaml:",inline,omitempty" jsonschema:"title=workflows to run,description=Workflows to run for the template" `
2021-05-01 18:28:24 +05:30
CompiledWorkflow * workflows . Workflow ` yaml:"-" json:"-" jsonschema:"-" `
2020-12-30 13:26:55 +05:30
2021-10-19 21:29:18 +05:30
// description: |
2021-10-19 22:28:48 +05:30
// Self Contained marks Requests for the template as self-contained
2023-02-07 16:10:40 +08:00
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" `
2021-11-29 16:01:06 +05:30
// description: |
// Stop execution once first match is found
2023-02-07 16:10:40 +08:00
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" `
2021-10-19 21:29:18 +05:30
2021-11-17 01:28:35 +01:00
// description: |
// Signature is the request signature method
2024-03-29 13:31:30 +05:30
// WARNING: 'signature' will be deprecated and will be removed in a future release. Prefer using 'code' protocol for writing cloud checks
2021-11-17 01:28:35 +01:00
// values:
// - "AWS"
2024-03-27 23:52:08 +05:30
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" `
2021-10-19 21:29:18 +05:30
2022-03-31 00:54:35 +05:30
// description: |
// Variables contains any variables for the current request.
2024-03-27 23:52:08 +05:30
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" `
2022-03-31 00:54:35 +05:30
2023-05-25 18:32:35 +02:00
// description: |
2023-08-01 14:33:43 -04:00
// Constants contains any scalar constant for the current template
2024-03-27 23:52:08 +05:30
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" `
2023-05-25 18:32:35 +02:00
2020-12-29 18:02:45 +05:30
// TotalRequests is the total number of requests for the template.
2021-05-01 18:28:24 +05:30
TotalRequests int ` yaml:"-" json:"-" `
2020-12-29 18:02:45 +05:30
// Executer is the actual template executor for running template requests
2021-05-01 18:28:24 +05:30
Executer protocols . Executer ` yaml:"-" json:"-" `
2021-06-05 23:00:59 +05:30
Path string ` yaml:"-" json:"-" `
2023-02-25 23:24:46 +01:00
// Verified defines if the template signature is digitally verified
Verified bool ` yaml:"-" json:"-" `
2024-04-01 19:18:21 +05:30
// TemplateVerifier is identifier verifier used to verify the template (default nuclei-templates have projectdiscovery/nuclei-templates)
TemplateVerifier string ` yaml:"-" json:"-" `
2023-08-31 18:03:01 +05:30
// RequestsQueue contains all template requests in order (both protocol & request order)
RequestsQueue [ ] protocols . Request ` yaml:"-" json:"-" `
2023-10-13 13:17:27 +05:30
// ImportedFiles contains list of files whose contents are imported after template was compiled
ImportedFiles [ ] string ` yaml:"-" json:"-" `
2021-10-27 15:53:04 +05:30
}
// Type returns the type of the template
2021-11-25 16:57:43 +02:00
func ( template * Template ) Type ( ) types . ProtocolType {
2021-10-27 15:53:04 +05:30
switch {
2021-11-25 16:57:43 +02:00
case len ( template . RequestsDNS ) > 0 :
2021-11-03 17:18:35 +05:30
return types . DNSProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsFile ) > 0 :
2021-11-03 17:18:35 +05:30
return types . FileProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsHTTP ) > 0 :
2021-11-03 17:18:35 +05:30
return types . HTTPProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsHeadless ) > 0 :
2021-11-03 17:18:35 +05:30
return types . HeadlessProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsNetwork ) > 0 :
2021-11-03 17:18:35 +05:30
return types . NetworkProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsSSL ) > 0 :
2021-11-03 18:58:00 +05:30
return types . SSLProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsWebsocket ) > 0 :
2021-11-03 18:58:00 +05:30
return types . WebsocketProtocol
2021-12-16 17:08:02 +05:30
case len ( template . RequestsWHOIS ) > 0 :
return types . WHOISProtocol
2023-06-09 17:24:24 +02:00
case len ( template . RequestsCode ) > 0 :
return types . CodeProtocol
2023-09-16 16:02:17 +05:30
case len ( template . RequestsJavascript ) > 0 :
return types . JavascriptProtocol
2025-07-01 00:40:44 +07:00
case len ( template . Workflows ) > 0 :
2024-06-22 19:12:00 +02:00
return types . WorkflowProtocol
2021-10-27 15:53:04 +05:30
default :
2021-11-03 17:18:35 +05:30
return types . InvalidProtocol
2021-10-27 15:53:04 +05:30
}
}
2021-12-16 11:09:38 +01:00
2024-03-14 03:08:53 +05:30
// IsFuzzing returns true if the template is a fuzzing template
func ( template * Template ) IsFuzzing ( ) bool {
if len ( template . RequestsHTTP ) == 0 && len ( template . RequestsHeadless ) == 0 {
// fuzzing is only supported for http and headless protocols
return false
}
if len ( template . RequestsHTTP ) > 0 {
for _ , request := range template . RequestsHTTP {
if len ( request . Fuzzing ) > 0 {
return true
}
}
}
if len ( template . RequestsHeadless ) > 0 {
for _ , request := range template . RequestsHeadless {
if len ( request . Fuzzing ) > 0 {
return true
}
}
}
return false
}
2024-03-29 13:31:30 +05:30
// UsesRequestSignature returns true if the template uses a request signature like AWS
func ( template * Template ) UsesRequestSignature ( ) bool {
return template . Signature . Value . String ( ) != ""
}
2023-10-13 13:17:27 +05:30
// HasCodeProtocol returns true if the template has a code protocol section
func ( template * Template ) HasCodeProtocol ( ) bool {
return len ( template . RequestsCode ) > 0
}
2023-08-31 18:03:01 +05:30
// validateAllRequestIDs check if that protocol already has given id if not
// then is is manually set to proto_index
func ( template * Template ) validateAllRequestIDs ( ) {
// this is required in multiprotocol and flow where we save response variables
// and all other data in template context if template as two requests in a protocol
// then it is overwritten to avoid this we use proto_index as request ID
if len ( template . RequestsCode ) > 1 {
for i , req := range template . RequestsCode {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
2023-10-13 13:17:27 +05:30
2023-08-31 18:03:01 +05:30
if len ( template . RequestsDNS ) > 1 {
for i , req := range template . RequestsDNS {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsFile ) > 1 {
for i , req := range template . RequestsFile {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsHTTP ) > 1 {
for i , req := range template . RequestsHTTP {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsHeadless ) > 1 {
for i , req := range template . RequestsHeadless {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsNetwork ) > 1 {
for i , req := range template . RequestsNetwork {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsSSL ) > 1 {
for i , req := range template . RequestsSSL {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsWebsocket ) > 1 {
for i , req := range template . RequestsWebsocket {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
if len ( template . RequestsWHOIS ) > 1 {
for i , req := range template . RequestsWHOIS {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-08-31 18:03:01 +05:30
}
}
}
2023-09-16 16:02:17 +05:30
if len ( template . RequestsJavascript ) > 1 {
for i , req := range template . RequestsJavascript {
if req . ID == "" {
2023-10-13 13:17:27 +05:30
req . ID = req . Type ( ) . String ( ) + "_" + strconv . Itoa ( i + 1 )
2023-09-16 16:02:17 +05:30
}
}
}
2023-08-31 18:03:01 +05:30
}
2021-12-16 11:09:38 +01:00
// MarshalYAML forces recursive struct validation during marshal operation
func ( template * Template ) MarshalYAML ( ) ( [ ] byte , error ) {
out , marshalErr := yaml . Marshal ( template )
2025-08-02 15:54:15 +05:30
// Use shared validator to avoid rebuilding struct cache for every template marshal
errValidate := tplValidator . Struct ( template )
2021-12-16 11:09:38 +01:00
return out , multierr . Append ( marshalErr , errValidate )
}
2025-03-26 11:03:43 +08:00
// UnmarshalYAML forces recursive struct validation after unmarshal operation
2021-12-16 11:09:38 +01:00
func ( template * Template ) UnmarshalYAML ( unmarshal func ( interface { } ) error ) error {
type Alias Template
alias := & Alias { }
err := unmarshal ( alias )
if err != nil {
return err
}
* template = Template ( * alias )
2023-03-21 00:48:35 +05:30
2024-06-16 04:27:31 +05:30
if ! ReTemplateID . MatchString ( template . ID ) {
2025-08-25 15:06:58 +07:00
return errkit . New ( "template id must match expression %v" , ReTemplateID , "tag" , "invalid_template" )
2024-06-16 04:27:31 +05:30
}
info := template . Info
if utils . IsBlank ( info . Name ) {
2025-08-25 15:06:58 +07:00
return errkit . New ( "no template name field provided" , "tag" , "invalid_template" )
2024-06-16 04:27:31 +05:30
}
if info . Authors . IsEmpty ( ) {
2025-08-25 15:06:58 +07:00
return errkit . New ( "no template author field provided" , "tag" , "invalid_template" )
2024-06-16 04:27:31 +05:30
}
2023-05-04 01:43:41 +05:30
if len ( template . RequestsHTTP ) > 0 || len ( template . RequestsNetwork ) > 0 {
2023-06-09 02:28:40 +08:00
_ = deprecatedProtocolNameTemplates . Set ( template . ID , true )
2023-05-04 01:43:41 +05:30
}
2023-03-21 00:48:35 +05:30
if len ( alias . RequestsHTTP ) > 0 && len ( alias . RequestsWithHTTP ) > 0 {
2025-08-25 15:06:58 +07:00
return errkit . New ( "use http or requests, both are not supported" , "tag" , "invalid_template" )
2023-03-21 00:48:35 +05:30
}
if len ( alias . RequestsNetwork ) > 0 && len ( alias . RequestsWithTCP ) > 0 {
2025-08-25 15:06:58 +07:00
return errkit . New ( "use tcp or network, both are not supported" , "tag" , "invalid_template" )
2023-03-21 00:48:35 +05:30
}
if len ( alias . RequestsWithHTTP ) > 0 {
template . RequestsHTTP = alias . RequestsWithHTTP
}
if len ( alias . RequestsWithTCP ) > 0 {
template . RequestsNetwork = alias . RequestsWithTCP
}
2025-08-02 15:54:15 +05:30
err = tplValidator . Struct ( template )
2023-06-09 19:52:56 +05:30
if err != nil {
return err
}
2023-08-31 18:03:01 +05:30
// check if the template contains more than 1 protocol request
// if so preserve the order of the protocols and requests
if template . hasMultipleRequests ( ) {
2023-06-09 19:52:56 +05:30
var tempmap yaml . MapSlice
err = unmarshal ( & tempmap )
if err != nil {
2025-08-25 15:06:58 +07:00
return errkit . Wrapf ( err , "failed to unmarshal multi protocol template %s" , template . ID )
2023-06-09 19:52:56 +05:30
}
arr := [ ] string { }
for _ , v := range tempmap {
key , ok := v . Key . ( string )
if ! ok {
continue
}
arr = append ( arr , key )
}
// add protocols to the protocol stack (the idea is to preserve the order of the protocols)
2023-08-31 18:03:01 +05:30
template . addRequestsToQueue ( arr ... )
2023-06-09 19:52:56 +05:30
}
return nil
}
2023-10-13 13:17:27 +05:30
// ImportFileRefs checks if sensitive fields like `flow` , `source` in code protocol are referencing files
// instead of actual javascript / engine code if so it loads the file contents and replaces the reference
func ( template * Template ) ImportFileRefs ( options * protocols . ExecutorOptions ) error {
var errs [ ] error
loadFile := func ( source string ) ( string , bool ) {
// load file respecting sandbox
data , err := options . Options . LoadHelperFile ( source , options . TemplatePath , options . Catalog )
if err == nil {
2025-07-01 00:40:44 +07:00
defer func ( ) {
_ = data . Close ( )
} ( )
2023-10-13 13:17:27 +05:30
bin , err := io . ReadAll ( data )
if err == nil {
return string ( bin ) , true
} else {
errs = append ( errs , err )
}
} else {
errs = append ( errs , err )
}
return "" , false
}
// for code protocol requests
for _ , request := range template . RequestsCode {
// simple test to check if source is a file or a snippet
if len ( strings . Split ( request . Source , "\n" ) ) == 1 && fileutil . FileExists ( request . Source ) {
if val , ok := loadFile ( request . Source ) ; ok {
template . ImportedFiles = append ( template . ImportedFiles , request . Source )
request . Source = val
}
}
}
2024-03-01 16:38:56 +05:30
// for javascript protocol code references
for _ , request := range template . RequestsJavascript {
// simple test to check if source is a file or a snippet
if len ( strings . Split ( request . Code , "\n" ) ) == 1 && fileutil . FileExists ( request . Code ) {
if val , ok := loadFile ( request . Code ) ; ok {
template . ImportedFiles = append ( template . ImportedFiles , request . Code )
request . Code = val
}
}
}
2023-10-13 13:17:27 +05:30
// flow code references
if template . Flow != "" {
if len ( template . Flow ) > 0 && filepath . Ext ( template . Flow ) == ".js" && fileutil . FileExists ( template . Flow ) {
if val , ok := loadFile ( template . Flow ) ; ok {
template . ImportedFiles = append ( template . ImportedFiles , template . Flow )
template . Flow = val
}
}
options . Flow = template . Flow
}
// for multiprotocol requests
// mutually exclusive with flow
if len ( template . RequestsQueue ) > 0 && template . Flow == "" {
// this is most likely a multiprotocol template
for _ , req := range template . RequestsQueue {
if req . Type ( ) == types . CodeProtocol {
request := req . ( * code . Request )
// simple test to check if source is a file or a snippet
if len ( strings . Split ( request . Source , "\n" ) ) == 1 && fileutil . FileExists ( request . Source ) {
if val , ok := loadFile ( request . Source ) ; ok {
template . ImportedFiles = append ( template . ImportedFiles , request . Source )
request . Source = val
}
}
}
}
2024-03-01 16:38:56 +05:30
// for javascript protocol code references
for _ , req := range template . RequestsQueue {
if req . Type ( ) == types . JavascriptProtocol {
request := req . ( * javascript . Request )
// simple test to check if source is a file or a snippet
if len ( strings . Split ( request . Code , "\n" ) ) == 1 && fileutil . FileExists ( request . Code ) {
if val , ok := loadFile ( request . Code ) ; ok {
template . ImportedFiles = append ( template . ImportedFiles , request . Code )
request . Code = val
}
}
}
}
2023-10-13 13:17:27 +05:30
}
return multierr . Combine ( errs ... )
}
// GetFileImports returns a list of files that are imported by the template
func ( template * Template ) GetFileImports ( ) [ ] string {
return template . ImportedFiles
}
2025-03-26 11:03:43 +08:00
// addRequestsToQueue adds protocol requests to the queue and preserves order of the protocols and requests
2023-08-31 18:03:01 +05:30
func ( template * Template ) addRequestsToQueue ( keys ... string ) {
2023-06-09 19:52:56 +05:30
for _ , key := range keys {
switch key {
case types . DNSProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsDNS ) ... )
2023-06-09 19:52:56 +05:30
case types . FileProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsFile ) ... )
2023-06-09 19:52:56 +05:30
case types . HTTPProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsHTTP ) ... )
2023-06-09 19:52:56 +05:30
case types . HeadlessProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsHeadless ) ... )
2023-06-09 19:52:56 +05:30
case types . NetworkProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsNetwork ) ... )
2023-06-09 19:52:56 +05:30
case types . SSLProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsSSL ) ... )
2023-06-09 19:52:56 +05:30
case types . WebsocketProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsWebsocket ) ... )
2023-06-09 19:52:56 +05:30
case types . WHOISProtocol . String ( ) :
2023-08-31 18:03:01 +05:30
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsWHOIS ) ... )
case types . CodeProtocol . String ( ) :
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsCode ) ... )
2023-09-16 16:02:17 +05:30
case types . JavascriptProtocol . String ( ) :
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsJavascript ) ... )
2023-08-31 18:03:01 +05:30
// for deprecated protocols
case "requests" :
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsHTTP ) ... )
case "network" :
template . RequestsQueue = append ( template . RequestsQueue , template . convertRequestToProtocolsRequest ( template . RequestsNetwork ) ... )
2023-06-09 19:52:56 +05:30
}
}
}
2023-08-31 18:03:01 +05:30
// hasMultipleRequests checks if the template has multiple requests
// if so it preserves the order of the request during compile and execution
func ( template * Template ) hasMultipleRequests ( ) bool {
2023-06-09 19:52:56 +05:30
counter := len ( template . RequestsDNS ) + len ( template . RequestsFile ) +
len ( template . RequestsHTTP ) + len ( template . RequestsHeadless ) +
len ( template . RequestsNetwork ) + len ( template . RequestsSSL ) +
2023-09-16 16:02:17 +05:30
len ( template . RequestsWebsocket ) + len ( template . RequestsWHOIS ) +
len ( template . RequestsCode ) + len ( template . RequestsJavascript )
2023-06-09 19:52:56 +05:30
return counter > 1
2021-12-16 11:09:38 +01:00
}
// MarshalJSON forces recursive struct validation during marshal operation
func ( template * Template ) MarshalJSON ( ) ( [ ] byte , error ) {
2024-12-19 18:06:21 +03:00
type TemplateAlias Template //avoid recursion
out , marshalErr := json . Marshal ( ( * TemplateAlias ) ( template ) )
2025-08-02 15:54:15 +05:30
errValidate := tplValidator . Struct ( template )
2021-12-16 11:09:38 +01:00
return out , multierr . Append ( marshalErr , errValidate )
}
// UnmarshalJSON forces recursive struct validation after unmarshal operation
func ( template * Template ) UnmarshalJSON ( data [ ] byte ) error {
type Alias Template
alias := & Alias { }
err := json . Unmarshal ( data , alias )
if err != nil {
return err
}
* template = Template ( * alias )
2025-08-02 15:54:15 +05:30
err = tplValidator . Struct ( template )
2023-06-09 19:52:56 +05:30
if err != nil {
return err
}
2023-08-31 18:03:01 +05:30
// check if the template contains more than 1 protocol request
// if so preserve the order of the protocols and requests
if template . hasMultipleRequests ( ) {
2023-06-09 19:52:56 +05:30
var tempMap map [ string ] interface { }
err = json . Unmarshal ( data , & tempMap )
if err != nil {
2025-08-25 15:06:58 +07:00
return errkit . Wrapf ( err , "failed to unmarshal multi protocol template %s" , template . ID )
2023-06-09 19:52:56 +05:30
}
arr := [ ] string { }
for k := range tempMap {
arr = append ( arr , k )
}
2023-08-31 18:03:01 +05:30
template . addRequestsToQueue ( arr ... )
2023-06-09 19:52:56 +05:30
}
return nil
2021-12-16 11:09:38 +01:00
}
2024-11-19 19:30:28 +03:00
// HasFileProtocol returns true if the template has a file protocol section
func ( template * Template ) HasFileProtocol ( ) bool {
return len ( template . RequestsFile ) > 0
}