-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathconfig.go
222 lines (189 loc) · 5.96 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package gbounty
import (
"encoding/json"
"io"
"reflect"
)
// Never obfuscate the Config type.
var _ = reflect.TypeOf(Config{})
// Config defines the configuration used by the scanner to perform a [scan].
// It includes options to control the scanner's behavior, such as the rate of
// requests per second, the concurrency level, and the output format.
type Config struct {
RPS int `default:"100"`
Concurrency int `default:"100"`
Version string
SaveOnStop bool
InMemory bool
BlindHost string
BlindHostKey string
EmailAddress bool
CustomTokens map[string]string
PayloadStrategy PayloadStrategy
Silent bool
StreamErrors bool
StreamMatches bool
ShowResponses bool
ShowErrors bool
ShowAll bool
ShowAllRequests bool
ShowAllResponses bool
OnlyProofOfConcept bool
OutPath string
OutFormat string
}
// Clone returns a deep copy of the [Config] instance.
func (c Config) Clone() Config {
clonedTokens := make(map[string]string)
for key, value := range c.CustomTokens {
clonedTokens[key] = value
}
return Config{
RPS: c.RPS,
Concurrency: c.Concurrency,
Version: c.Version,
SaveOnStop: c.SaveOnStop,
InMemory: c.InMemory,
BlindHost: c.BlindHost,
BlindHostKey: c.BlindHostKey,
EmailAddress: c.EmailAddress,
CustomTokens: clonedTokens,
PayloadStrategy: c.PayloadStrategy,
Silent: c.Silent,
StreamErrors: c.StreamErrors,
StreamMatches: c.StreamMatches,
ShowResponses: c.ShowResponses,
ShowErrors: c.ShowErrors,
ShowAll: c.ShowAll,
ShowAllRequests: c.ShowAllRequests,
ShowAllResponses: c.ShowAllResponses,
OutPath: c.OutPath,
OutFormat: c.OutFormat,
}
}
// BlindHostConfigured returns whether the blind host and its key are configured.
func (c Config) BlindHostConfigured() bool {
return len(c.BlindHost) > 0 && len(c.BlindHostKey) > 0
}
// CfgOption is a function that modifies a [Config] instance.
// See [WithRPS] and [WithConcurrency] as examples.
type CfgOption func(*Config)
// WithRPS sets the rate of requests per second.
func WithRPS(rps int) CfgOption {
return func(cfg *Config) {
cfg.RPS = rps
}
}
// WithConcurrency sets the concurrency level.
func WithConcurrency(concurrency int) CfgOption {
return func(cfg *Config) {
cfg.Concurrency = concurrency
}
}
// WithBlindHost sets the blind host.
func WithBlindHost(blindHost string) CfgOption {
return func(cfg *Config) {
cfg.BlindHost = blindHost
}
}
// WithBlindHostKey sets the blind host key.
func WithBlindHostKey(blindHostKey string) CfgOption {
return func(cfg *Config) {
cfg.BlindHostKey = blindHostKey
}
}
// WithCustomTokens sets the custom tokens.
func WithCustomTokens(customTokens map[string]string) CfgOption {
return func(cfg *Config) {
cfg.CustomTokens = customTokens
}
}
// WithPayloadStrategy sets the payload strategy.
func WithPayloadStrategy(ps string) CfgOption {
return func(cfg *Config) {
// Attention, please.
// PayloadStrategyFromString defaults to
// PayloadStrategyAll (performance implications).
cfg.PayloadStrategy = PayloadStrategyFromString(ps)
}
}
// CfgOptionsFromJSON parses a JSON document from a [io.Reader],
// and turn its contents into a slice of [CfgOption].
//
// The expected payload is slightly different from [Config] struct.
//
// For instance, it uses pointers to make it easier to determine
// whether a value was set or not.
//
// Also, note that the parameter names is slightly different as well.
// The latter uses long, camel-cased names.
func CfgOptionsFromJSON(r io.Reader) ([]CfgOption, error) {
var cfg struct {
Concurrency *int `json:"concurrency"`
RequestPerSecond *int `json:"requestPerSecond"`
BlindHost *string `json:"blindHost"`
BlindHostKey *string `json:"blindHostKey"`
CustomTokens map[string]string `json:"tokens"`
PayloadStrategy *string `json:"payloadStrategy"`
}
err := json.NewDecoder(r).Decode(&cfg)
if err != nil {
return nil, err
}
const totalOpts = 6
opts := make([]CfgOption, 0, totalOpts)
if cfg.Concurrency != nil && *cfg.Concurrency > 0 {
opts = append(opts, WithConcurrency(*cfg.Concurrency))
}
if cfg.RequestPerSecond != nil && *cfg.RequestPerSecond > 0 {
opts = append(opts, WithRPS(*cfg.RequestPerSecond))
}
if cfg.BlindHost != nil && len(*cfg.BlindHost) > 0 {
opts = append(opts, WithBlindHost(*cfg.BlindHost))
}
if cfg.BlindHostKey != nil && len(*cfg.BlindHostKey) > 0 {
opts = append(opts, WithBlindHostKey(*cfg.BlindHostKey))
}
if cfg.CustomTokens != nil && len(cfg.CustomTokens) > 0 {
opts = append(opts, WithCustomTokens(cfg.CustomTokens))
}
if cfg.PayloadStrategy != nil && len(*cfg.PayloadStrategy) > 0 {
opts = append(opts, WithPayloadStrategy(*cfg.PayloadStrategy))
}
return opts, nil
}
const (
PayloadStrategyOnlyOnce PayloadStrategy = "only_once"
PayloadStrategyAll PayloadStrategy = "all"
)
// PayloadStrategy represents the strategy used to inject payloads
// during the scan execution. It can be either [PayloadStrategyOnlyOnce]
// or [PayloadStrategyAll].
type PayloadStrategy string
// PayloadStrategyFromString converts a string into a [PayloadStrategy].
func PayloadStrategyFromString(s string) PayloadStrategy {
switch s {
case string(PayloadStrategyOnlyOnce):
return PayloadStrategyOnlyOnce
default:
// Use [PayloadStrategyAll] as the default value
// for every other.
return PayloadStrategyAll
}
}
// IsOnlyOnce returns whether the payload strategy is [PayloadStrategyOnlyOnce].
func (ps PayloadStrategy) IsOnlyOnce() bool {
return ps == PayloadStrategyOnlyOnce
}
// String returns the string representation of the [PayloadStrategy].
func (ps PayloadStrategy) String() string {
switch ps {
case PayloadStrategyOnlyOnce:
return string(PayloadStrategyOnlyOnce)
case PayloadStrategyAll:
return string(PayloadStrategyAll)
default:
return unknown
}
}
const unknown = "Unknown"