Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/testutils/testutils.go
2843 views
1
package testutils
2
3
import (
4
"context"
5
"encoding/base64"
6
"os"
7
"time"
8
9
"github.com/projectdiscovery/ratelimit"
10
"go.uber.org/multierr"
11
12
"github.com/logrusorgru/aurora"
13
14
"github.com/projectdiscovery/gologger/levels"
15
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
16
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
17
"github.com/projectdiscovery/nuclei/v3/pkg/model"
18
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
19
"github.com/projectdiscovery/nuclei/v3/pkg/output"
20
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
21
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
22
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
23
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
24
protocolUtils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
25
"github.com/projectdiscovery/nuclei/v3/pkg/types"
26
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
27
unitutils "github.com/projectdiscovery/utils/unit"
28
)
29
30
// Init initializes the protocols and their configurations
31
func Init(options *types.Options) {
32
_ = protocolstate.Init(options)
33
_ = protocolinit.Init(options)
34
}
35
36
// Cleanup cleans up the protocols and their configurations
37
func Cleanup(options *types.Options) {
38
protocolstate.Close(options.ExecutionId)
39
}
40
41
// DefaultOptions is the default options structure for nuclei during mocking.
42
var DefaultOptions = &types.Options{
43
Metrics: false,
44
Debug: false,
45
DebugRequests: false,
46
DebugResponse: false,
47
Silent: false,
48
Verbose: false,
49
NoColor: true,
50
UpdateTemplates: false,
51
JSONL: false,
52
OmitRawRequests: false,
53
EnableProgressBar: false,
54
TemplateList: false,
55
Stdin: false,
56
StopAtFirstMatch: false,
57
NoMeta: false,
58
Project: false,
59
MetricsPort: 0,
60
BulkSize: 25,
61
TemplateThreads: 10,
62
Timeout: 5,
63
Retries: 1,
64
RateLimit: 150,
65
RateLimitDuration: time.Second,
66
ProbeConcurrency: 50,
67
ProjectPath: "",
68
Severities: severity.Severities{},
69
Targets: []string{},
70
TargetsFilePath: "",
71
Output: "",
72
Proxy: []string{},
73
TraceLogFile: "",
74
Templates: []string{},
75
ExcludedTemplates: []string{},
76
CustomHeaders: []string{},
77
InteractshURL: "https://oast.fun",
78
InteractionsCacheSize: 5000,
79
InteractionsEviction: 60,
80
InteractionsCoolDownPeriod: 5,
81
InteractionsPollDuration: 5,
82
GitHubTemplateRepo: []string{},
83
GitHubToken: "",
84
}
85
86
// TemplateInfo contains info for a mock executed template.
87
type TemplateInfo struct {
88
ID string
89
Info model.Info
90
Path string
91
}
92
93
// NewMockExecuterOptions creates a new mock executeroptions struct
94
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecutorOptions {
95
progressImpl, _ := progress.NewStatsTicker(0, false, false, false, 0)
96
executerOpts := &protocols.ExecutorOptions{
97
Output: NewMockOutputWriter(options.OmitTemplate),
98
Options: options,
99
Progress: progressImpl,
100
ProjectFile: nil,
101
IssuesClient: nil,
102
Browser: nil,
103
Catalog: disk.NewCatalog(config.DefaultConfig.TemplatesDirectory),
104
RateLimiter: ratelimit.New(context.Background(), uint(options.RateLimit), time.Second),
105
}
106
107
if info != nil {
108
executerOpts.TemplateInfo = info.Info
109
executerOpts.TemplateID = info.ID
110
executerOpts.TemplatePath = info.Path
111
}
112
113
executerOpts.CreateTemplateCtxStore()
114
115
return executerOpts
116
}
117
118
// NoopWriter is a NooP gologger writer.
119
type NoopWriter struct{}
120
121
// Write writes the data to an output writer.
122
func (n *NoopWriter) Write(data []byte, level levels.Level) {}
123
124
// MockOutputWriter is a mocked output writer.
125
type MockOutputWriter struct {
126
aurora aurora.Aurora
127
omitTemplate bool
128
RequestCallback func(templateID, url, requestType string, err error)
129
FailureCallback func(result *output.InternalEvent)
130
WriteCallback func(o *output.ResultEvent)
131
}
132
133
// NewMockOutputWriter creates a new mock output writer
134
func NewMockOutputWriter(omomitTemplate bool) *MockOutputWriter {
135
return &MockOutputWriter{aurora: aurora.NewAurora(false), omitTemplate: omomitTemplate}
136
}
137
138
// Close closes the output writer interface
139
func (m *MockOutputWriter) Close() {}
140
141
// Colorizer returns the colorizer instance for writer
142
func (m *MockOutputWriter) Colorizer() aurora.Aurora {
143
return m.aurora
144
}
145
146
func (m *MockOutputWriter) ResultCount() int {
147
return 0
148
}
149
150
// Write writes the event to file and/or screen.
151
func (m *MockOutputWriter) Write(result *output.ResultEvent) error {
152
if m.WriteCallback != nil {
153
m.WriteCallback(result)
154
}
155
return nil
156
}
157
158
// Request writes a log the requests trace log
159
func (m *MockOutputWriter) Request(templateID, url, requestType string, err error) {
160
if m.RequestCallback != nil {
161
m.RequestCallback(templateID, url, requestType, err)
162
}
163
}
164
165
// WriteFailure writes the event to file and/or screen.
166
func (m *MockOutputWriter) WriteFailure(wrappedEvent *output.InternalWrappedEvent) error {
167
// if failure event has more than one result, write them all
168
if len(wrappedEvent.Results) > 0 {
169
errs := []error{}
170
for _, result := range wrappedEvent.Results {
171
result.MatcherStatus = false // just in case
172
if err := m.Write(result); err != nil {
173
errs = append(errs, err)
174
}
175
}
176
if len(errs) > 0 {
177
return multierr.Combine(errs...)
178
}
179
return nil
180
}
181
182
// create event
183
event := wrappedEvent.InternalEvent
184
templatePath, templateURL := utils.TemplatePathURL(types.ToString(event["template-path"]), types.ToString(event["template-id"]), types.ToString(event["template-verifier"]))
185
var templateInfo model.Info
186
if ti, ok := event["template-info"].(model.Info); ok {
187
templateInfo = ti
188
}
189
fields := protocolUtils.GetJsonFieldsFromURL(types.ToString(event["host"]))
190
if types.ToString(event["ip"]) != "" {
191
fields.Ip = types.ToString(event["ip"])
192
}
193
if types.ToString(event["path"]) != "" {
194
fields.Path = types.ToString(event["path"])
195
}
196
data := &output.ResultEvent{
197
Template: templatePath,
198
TemplateURL: templateURL,
199
TemplateID: types.ToString(event["template-id"]),
200
TemplatePath: types.ToString(event["template-path"]),
201
Info: templateInfo,
202
Type: types.ToString(event["type"]),
203
Path: fields.Path,
204
Host: fields.Host,
205
Port: fields.Port,
206
Scheme: fields.Scheme,
207
URL: fields.URL,
208
IP: fields.Ip,
209
Request: types.ToString(event["request"]),
210
Response: types.ToString(event["response"]),
211
MatcherStatus: false,
212
Timestamp: time.Now(),
213
//FIXME: this is workaround to encode the template when no results were found
214
TemplateEncoded: m.encodeTemplate(types.ToString(event["template-path"])),
215
Error: types.ToString(event["error"]),
216
}
217
return m.Write(data)
218
}
219
220
func (m *MockOutputWriter) RequestStatsLog(statusCode, response string) {}
221
222
var maxTemplateFileSizeForEncoding = unitutils.Mega
223
224
func (w *MockOutputWriter) encodeTemplate(templatePath string) string {
225
data, err := os.ReadFile(templatePath)
226
if err == nil && !w.omitTemplate && len(data) <= maxTemplateFileSizeForEncoding && config.DefaultConfig.IsCustomTemplate(templatePath) {
227
return base64.StdEncoding.EncodeToString(data)
228
}
229
return ""
230
}
231
232
func (m *MockOutputWriter) WriteStoreDebugData(host, templateID, eventType string, data string) {}
233
234
type MockProgressClient struct{}
235
236
// Stop stops the progress recorder.
237
func (m *MockProgressClient) Stop() {}
238
239
// Init inits the progress bar with initial details for scan
240
func (m *MockProgressClient) Init(hostCount int64, rulesCount int, requestCount int64) {}
241
242
// AddToTotal adds a value to the total request count
243
func (m *MockProgressClient) AddToTotal(delta int64) {}
244
245
// IncrementRequests increments the requests counter by 1.
246
func (m *MockProgressClient) IncrementRequests() {}
247
248
// SetRequests sets the counter by incrementing it with a delta
249
func (m *MockProgressClient) SetRequests(count uint64) {}
250
251
// IncrementMatched increments the matched counter by 1.
252
func (m *MockProgressClient) IncrementMatched() {}
253
254
// IncrementErrorsBy increments the error counter by count.
255
func (m *MockProgressClient) IncrementErrorsBy(count int64) {}
256
257
// IncrementFailedRequestsBy increments the number of requests counter by count
258
// along with errors.
259
func (m *MockProgressClient) IncrementFailedRequestsBy(count int64) {}
260
261