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