Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/input/provider/interface.go
2850 views
1
package provider
2
3
import (
4
"errors"
5
"fmt"
6
"strings"
7
8
"github.com/projectdiscovery/gologger"
9
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
10
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats/openapi"
11
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats/swagger"
12
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider/http"
13
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider/list"
14
"github.com/projectdiscovery/nuclei/v3/pkg/input/types"
15
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
16
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
17
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
18
configTypes "github.com/projectdiscovery/nuclei/v3/pkg/types"
19
"github.com/projectdiscovery/retryablehttp-go"
20
"github.com/projectdiscovery/utils/errkit"
21
stringsutil "github.com/projectdiscovery/utils/strings"
22
)
23
24
var (
25
ErrNotImplemented = errkit.New("provider does not implement method")
26
ErrInactiveInput = fmt.Errorf("input is inactive")
27
)
28
29
const (
30
MultiFormatInputProvider = "MultiFormatInputProvider"
31
ListInputProvider = "ListInputProvider"
32
SimpleListInputProvider = "SimpleInputProvider"
33
)
34
35
// IsErrNotImplemented checks if an error is a not implemented error
36
func IsErrNotImplemented(err error) bool {
37
if err == nil {
38
return false
39
}
40
if stringsutil.ContainsAll(err.Error(), "provider", "does not implement") {
41
return true
42
}
43
return false
44
}
45
46
// Validate all Implementations
47
var (
48
// SimpleInputProvider is more like a No-Op and returns given list of urls as input
49
_ InputProvider = &SimpleInputProvider{}
50
// HttpInputProvider provides support for formats that contain complete request/response
51
// like burp, openapi, postman,proxify, etc.
52
_ InputProvider = &http.HttpInputProvider{}
53
// ListInputProvider provides support for simple list of urls or files etc
54
_ InputProvider = &list.ListInputProvider{}
55
)
56
57
// InputProvider is unified input provider interface that provides
58
// processed inputs to nuclei by parsing and providing different
59
// formats such as list,openapi,postman,proxify,burp etc.
60
type InputProvider interface {
61
// Count returns total targets for input provider
62
Count() int64
63
// Iterate over all inputs in order
64
Iterate(callback func(value *contextargs.MetaInput) bool)
65
// Set adds item to input provider
66
Set(executionId string, value string)
67
// SetWithProbe adds item to input provider with http probing
68
SetWithProbe(executionId string, value string, probe types.InputLivenessProbe) error
69
// SetWithExclusions adds item to input provider if it doesn't match any of the exclusions
70
SetWithExclusions(executionId string, value string) error
71
// InputType returns the type of input provider
72
InputType() string
73
// Close the input provider and cleanup any resources
74
Close()
75
}
76
77
// InputOptions contains options for input provider
78
type InputOptions struct {
79
// Options for global config
80
Options *configTypes.Options
81
// TempDir is the temporary directory for storing files
82
TempDir string
83
// NotFoundCallback is the callback to call when input is not found
84
// only supported in list input provider
85
NotFoundCallback func(template string) bool
86
}
87
88
// NewInputProvider creates a new input provider based on the options
89
// and returns it
90
func NewInputProvider(opts InputOptions) (InputProvider, error) {
91
// optionally load generated vars values if available
92
val, err := formats.ReadOpenAPIVarDumpFile()
93
if err != nil && !errors.Is(err, formats.ErrNoVarsDumpFile) {
94
// log error and continue
95
gologger.Error().Msgf("Could not read vars dump file: %s\n", err)
96
}
97
extraVars := make(map[string]interface{})
98
if val != nil {
99
for _, v := range val.Var {
100
v = strings.TrimSpace(v)
101
// split into key value
102
parts := strings.SplitN(v, "=", 2)
103
if len(parts) == 2 {
104
extraVars[parts[0]] = parts[1]
105
}
106
}
107
}
108
109
// check if input provider is supported
110
if strings.EqualFold(opts.Options.InputFileMode, "list") {
111
// create a new list input provider
112
return list.New(&list.Options{
113
Options: opts.Options,
114
NotFoundCallback: opts.NotFoundCallback,
115
})
116
} else if len(opts.Options.Targets) > 0 &&
117
(strings.EqualFold(opts.Options.InputFileMode, "openapi") || strings.EqualFold(opts.Options.InputFileMode, "swagger")) {
118
119
if len(opts.Options.Targets) > 1 {
120
return nil, fmt.Errorf("only one target URL is supported in %s input mode", opts.Options.InputFileMode)
121
}
122
123
target := opts.Options.Targets[0]
124
if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") {
125
var downloader formats.SpecDownloader
126
var tempFile string
127
var err error
128
129
// Get HttpClient from protocolstate if available
130
var httpClient *retryablehttp.Client
131
if opts.Options.ExecutionId != "" {
132
dialers := protocolstate.GetDialersWithId(opts.Options.ExecutionId)
133
if dialers != nil {
134
httpClient = dialers.DefaultHTTPClient
135
}
136
}
137
138
switch strings.ToLower(opts.Options.InputFileMode) {
139
case "openapi":
140
downloader = openapi.NewDownloader()
141
tempFile, err = downloader.Download(target, opts.TempDir, httpClient)
142
case "swagger":
143
downloader = swagger.NewDownloader()
144
tempFile, err = downloader.Download(target, opts.TempDir, httpClient)
145
default:
146
return nil, fmt.Errorf("unsupported input mode: %s", opts.Options.InputFileMode)
147
}
148
149
if err != nil {
150
return nil, fmt.Errorf("failed to download %s spec from url %s: %w", opts.Options.InputFileMode, target, err)
151
}
152
153
opts.Options.TargetsFilePath = tempFile
154
}
155
}
156
157
return http.NewHttpInputProvider(&http.HttpMultiFormatOptions{
158
InputFile: opts.Options.TargetsFilePath,
159
InputMode: opts.Options.InputFileMode,
160
Options: formats.InputFormatOptions{
161
Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
162
SkipFormatValidation: opts.Options.SkipFormatValidation,
163
RequiredOnly: opts.Options.FormatUseRequiredOnly,
164
VarsTextTemplating: opts.Options.VarsTextTemplating,
165
VarsFilePaths: opts.Options.VarsFilePaths,
166
},
167
})
168
}
169
170
// SupportedInputFormats returns all supported input formats of nuclei
171
func SupportedInputFormats() string {
172
return "list, " + http.SupportedFormats()
173
}
174
175