Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/lib/sdk_private.go
2061 views
1
package nuclei
2
3
import (
4
"context"
5
"fmt"
6
"strings"
7
"sync"
8
"time"
9
10
"github.com/projectdiscovery/nuclei/v3/pkg/input"
11
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
12
13
"github.com/logrusorgru/aurora"
14
"github.com/pkg/errors"
15
"github.com/projectdiscovery/gologger"
16
"github.com/projectdiscovery/gologger/levels"
17
"github.com/projectdiscovery/httpx/common/httpx"
18
"github.com/projectdiscovery/nuclei/v3/internal/runner"
19
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
20
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
21
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
22
"github.com/projectdiscovery/nuclei/v3/pkg/core"
23
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
24
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
25
"github.com/projectdiscovery/nuclei/v3/pkg/output"
26
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
27
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
28
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
29
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
30
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
31
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
32
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
33
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
34
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
35
"github.com/projectdiscovery/nuclei/v3/pkg/types"
36
nucleiUtils "github.com/projectdiscovery/nuclei/v3/pkg/utils"
37
"github.com/projectdiscovery/ratelimit"
38
)
39
40
// applyRequiredDefaults to options
41
func (e *NucleiEngine) applyRequiredDefaults(ctx context.Context) {
42
mockoutput := testutils.NewMockOutputWriter(e.opts.OmitTemplate)
43
mockoutput.WriteCallback = func(event *output.ResultEvent) {
44
if len(e.resultCallbacks) > 0 {
45
for _, callback := range e.resultCallbacks {
46
if callback != nil {
47
callback(event)
48
}
49
}
50
return
51
}
52
sb := strings.Builder{}
53
sb.WriteString(fmt.Sprintf("[%v] ", event.TemplateID))
54
if event.Matched != "" {
55
sb.WriteString(event.Matched)
56
} else {
57
sb.WriteString(event.Host)
58
}
59
fmt.Println(sb.String())
60
}
61
if e.onFailureCallback != nil {
62
mockoutput.FailureCallback = e.onFailureCallback
63
}
64
65
if e.customWriter != nil {
66
e.customWriter = output.NewMultiWriter(e.customWriter, mockoutput)
67
} else {
68
e.customWriter = mockoutput
69
}
70
71
if e.customProgress == nil {
72
e.customProgress = &testutils.MockProgressClient{}
73
}
74
if e.hostErrCache == nil && e.opts.ShouldUseHostError() {
75
e.hostErrCache = hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount, nil)
76
}
77
// setup interactsh
78
if e.interactshOpts != nil {
79
e.interactshOpts.Output = e.customWriter
80
e.interactshOpts.Progress = e.customProgress
81
} else {
82
e.interactshOpts = interactsh.DefaultOptions(e.customWriter, e.rc, e.customProgress)
83
}
84
if e.rateLimiter == nil {
85
e.rateLimiter = ratelimit.New(ctx, 150, time.Second)
86
}
87
if e.opts.ExcludeTags == nil {
88
e.opts.ExcludeTags = []string{}
89
}
90
// these templates are known to have weak matchers
91
// and idea is to disable them to avoid false positives
92
e.opts.ExcludeTags = append(e.opts.ExcludeTags, config.ReadIgnoreFile().Tags...)
93
94
e.inputProvider = provider.NewSimpleInputProvider()
95
}
96
97
// init
98
func (e *NucleiEngine) init(ctx context.Context) error {
99
// Set a default logger if one isn't provided in the options
100
if e.opts.Logger != nil {
101
e.Logger = e.opts.Logger
102
} else {
103
e.opts.Logger = &gologger.Logger{}
104
}
105
e.Logger = e.opts.Logger
106
107
if e.opts.Verbose {
108
e.Logger.SetMaxLevel(levels.LevelVerbose)
109
} else if e.opts.Debug {
110
e.Logger.SetMaxLevel(levels.LevelDebug)
111
} else if e.opts.Silent {
112
e.Logger.SetMaxLevel(levels.LevelSilent)
113
}
114
115
if err := runner.ValidateOptions(e.opts); err != nil {
116
return err
117
}
118
119
if e.opts.Parser != nil {
120
if op, ok := e.opts.Parser.(*templates.Parser); ok {
121
e.parser = op
122
}
123
}
124
125
if e.parser == nil {
126
e.parser = templates.NewParser()
127
}
128
129
if protocolstate.ShouldInit(e.opts.ExecutionId) {
130
_ = protocolinit.Init(e.opts)
131
}
132
133
if e.opts.ProxyInternal && e.opts.AliveHttpProxy != "" || e.opts.AliveSocksProxy != "" {
134
httpclient, err := httpclientpool.Get(e.opts, &httpclientpool.Configuration{})
135
if err != nil {
136
return err
137
}
138
e.httpClient = httpclient
139
}
140
141
e.applyRequiredDefaults(ctx)
142
var err error
143
144
// setup progressbar
145
if e.enableStats {
146
progressInstance, progressErr := progress.NewStatsTicker(e.opts.StatsInterval, e.enableStats, e.opts.StatsJSON, false, e.opts.MetricsPort)
147
if progressErr != nil {
148
return err
149
}
150
e.customProgress = progressInstance
151
e.interactshOpts.Progress = progressInstance
152
}
153
154
if err := reporting.CreateConfigIfNotExists(); err != nil {
155
return err
156
}
157
// we don't support reporting config in sdk mode
158
if e.rc, err = reporting.New(&reporting.Options{}, "", false); err != nil {
159
return err
160
}
161
e.interactshOpts.IssuesClient = e.rc
162
if e.httpClient != nil {
163
e.interactshOpts.HTTPClient = e.httpClient
164
}
165
if e.interactshClient, err = interactsh.New(e.interactshOpts); err != nil {
166
return err
167
}
168
169
if e.catalog == nil {
170
e.catalog = disk.NewCatalog(config.DefaultConfig.TemplatesDirectory)
171
}
172
173
e.executerOpts = &protocols.ExecutorOptions{
174
Output: e.customWriter,
175
Options: e.opts,
176
Progress: e.customProgress,
177
Catalog: e.catalog,
178
IssuesClient: e.rc,
179
RateLimiter: e.rateLimiter,
180
Interactsh: e.interactshClient,
181
Colorizer: aurora.NewAurora(true),
182
ResumeCfg: types.NewResumeCfg(),
183
Browser: e.browserInstance,
184
Parser: e.parser,
185
InputHelper: input.NewHelper(),
186
Logger: e.opts.Logger,
187
}
188
if e.opts.ShouldUseHostError() && e.hostErrCache != nil {
189
e.executerOpts.HostErrorsCache = e.hostErrCache
190
}
191
if len(e.opts.SecretsFile) > 0 {
192
authTmplStore, err := runner.GetAuthTmplStore(e.opts, e.catalog, e.executerOpts)
193
if err != nil {
194
return errors.Wrap(err, "failed to load dynamic auth templates")
195
}
196
authOpts := &authprovider.AuthProviderOptions{SecretsFiles: e.opts.SecretsFile}
197
authOpts.LazyFetchSecret = runner.GetLazyAuthFetchCallback(&runner.AuthLazyFetchOptions{
198
TemplateStore: authTmplStore,
199
ExecOpts: e.executerOpts,
200
})
201
// initialize auth provider
202
provider, err := authprovider.NewAuthProvider(authOpts)
203
if err != nil {
204
return errors.Wrap(err, "could not create auth provider")
205
}
206
e.executerOpts.AuthProvider = provider
207
}
208
if e.authprovider != nil {
209
e.executerOpts.AuthProvider = e.authprovider
210
}
211
212
// prefetch secrets
213
if e.executerOpts.AuthProvider != nil && e.opts.PreFetchSecrets {
214
if err := e.executerOpts.AuthProvider.PreFetchSecrets(); err != nil {
215
return errors.Wrap(err, "could not prefetch secrets")
216
}
217
}
218
219
if e.executerOpts.RateLimiter == nil {
220
if e.opts.RateLimitMinute > 0 {
221
e.opts.RateLimit = e.opts.RateLimitMinute
222
e.opts.RateLimitDuration = time.Minute
223
}
224
if e.opts.RateLimit > 0 && e.opts.RateLimitDuration == 0 {
225
e.opts.RateLimitDuration = time.Second
226
}
227
if e.opts.RateLimit == 0 && e.opts.RateLimitDuration == 0 {
228
e.executerOpts.RateLimiter = ratelimit.NewUnlimited(ctx)
229
} else {
230
e.executerOpts.RateLimiter = ratelimit.New(ctx, uint(e.opts.RateLimit), e.opts.RateLimitDuration)
231
}
232
}
233
234
// Handle the case where the user passed an existing parser that we can use as a cache
235
if e.opts.Parser != nil {
236
if cachedParser, ok := e.opts.Parser.(*templates.Parser); ok {
237
e.parser = cachedParser
238
e.opts.Parser = cachedParser
239
e.executerOpts.Parser = cachedParser
240
e.executerOpts.Options.Parser = cachedParser
241
}
242
}
243
244
// Create a new parser if necessary
245
if e.parser == nil {
246
op := templates.NewParser()
247
e.parser = op
248
e.opts.Parser = op
249
e.executerOpts.Parser = op
250
e.executerOpts.Options.Parser = op
251
}
252
253
e.engine = core.New(e.opts)
254
e.engine.SetExecuterOptions(e.executerOpts)
255
256
httpxOptions := httpx.DefaultOptions
257
httpxOptions.Timeout = 5 * time.Second
258
if client, err := httpx.New(&httpxOptions); err != nil {
259
return err
260
} else {
261
e.httpxClient = nucleiUtils.GetInputLivenessChecker(client)
262
}
263
264
// Only Happens once regardless how many times this function is called
265
// This will update ignore file to filter out templates with weak matchers to avoid false positives
266
// and also upgrade templates to latest version if available
267
installer.NucleiSDKVersionCheck()
268
269
if DefaultConfig.CanCheckForUpdates() {
270
return e.processUpdateCheckResults()
271
}
272
return nil
273
}
274
275
type syncOnce struct {
276
sync.Once
277
}
278
279
var updateCheckInstance = &syncOnce{}
280
281
// processUpdateCheckResults processes update check results
282
func (e *NucleiEngine) processUpdateCheckResults() error {
283
var err error
284
updateCheckInstance.Do(func() {
285
if e.onUpdateAvailableCallback != nil {
286
e.onUpdateAvailableCallback(config.DefaultConfig.LatestNucleiTemplatesVersion)
287
}
288
tm := installer.TemplateManager{}
289
err = tm.UpdateIfOutdated()
290
})
291
return err
292
}
293
294