Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/fuzz/component/value.go
2070 views
1
package component
2
3
import (
4
"reflect"
5
"strconv"
6
7
"github.com/leslie-qiwa/flat"
8
"github.com/logrusorgru/aurora"
9
"github.com/projectdiscovery/gologger"
10
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
11
)
12
13
// Value is a value component containing a single
14
// parameter for the component
15
//
16
// It is a type of container that is used to represent
17
// all the data values that are used in a request.
18
type Value struct {
19
data string
20
parsed dataformat.KV
21
dataFormat string
22
}
23
24
// NewValue returns a new value component
25
func NewValue(data string) *Value {
26
if data == "" {
27
return &Value{}
28
}
29
v := &Value{data: data}
30
31
// Do any dataformat decoding on the data if needed
32
decodedDataformat, err := dataformat.Decode(data)
33
if err == nil && decodedDataformat != nil {
34
v.SetParsed(decodedDataformat.Data, decodedDataformat.DataFormat)
35
}
36
return v
37
}
38
39
// Clones current state of this value
40
func (v *Value) Clone() *Value {
41
return &Value{
42
data: v.data,
43
parsed: v.parsed.Clone(),
44
dataFormat: v.dataFormat,
45
}
46
}
47
48
// String returns the string representation of the value
49
func (v *Value) String() string {
50
return v.data
51
}
52
53
// Parsed returns the parsed value
54
func (v *Value) Parsed() dataformat.KV {
55
return v.parsed
56
}
57
58
// SetParsed sets the parsed value map
59
func (v *Value) SetParsed(data dataformat.KV, dataFormat string) {
60
v.dataFormat = dataFormat
61
if data.OrderedMap != nil {
62
v.parsed = data
63
return
64
}
65
parsed := data.Map
66
flattened, err := flat.Flatten(parsed, flatOpts)
67
if err == nil {
68
v.parsed = dataformat.KVMap(flattened)
69
} else {
70
v.parsed = dataformat.KVMap(parsed)
71
}
72
}
73
74
// SetParsedValue sets the parsed value for a key
75
// in the parsed map
76
func (v *Value) SetParsedValue(key, value string) bool {
77
if key == "" {
78
return false
79
}
80
81
origValue := v.parsed.Get(key)
82
if origValue == nil {
83
v.parsed.Set(key, value)
84
return true
85
}
86
87
// TODO(dwisiswant0): I'm sure that this can be simplified because
88
// `dataformat.KV.*` is a type of `mapsutil.*` where the value is `any`. So,
89
// it looks like we won't type conversion here or even have its own methods
90
// inside `dataformat.KV`.
91
92
// If the value is a list, append to it
93
// otherwise replace it
94
switch v := origValue.(type) {
95
case []interface{}:
96
// update last value
97
if len(v) > 0 {
98
v[len(v)-1] = value
99
}
100
origValue = v
101
case string:
102
origValue = value
103
case int, int32, int64, float32, float64:
104
parsed, err := strconv.ParseInt(value, 10, 64)
105
if err != nil {
106
return false
107
}
108
origValue = parsed
109
case bool:
110
parsed, err := strconv.ParseBool(value)
111
if err != nil {
112
return false
113
}
114
origValue = parsed
115
default:
116
// explicitly check for typed slice
117
if val, ok := IsTypedSlice(v); ok {
118
if len(val) > 0 {
119
val[len(val)-1] = value
120
}
121
origValue = val
122
} else {
123
// make it default warning instead of error
124
gologger.DefaultLogger.Print().Msgf("[%v] unknown type %T for value %s", aurora.BrightYellow("WARN"), v, v)
125
}
126
}
127
v.parsed.Set(key, origValue)
128
return true
129
}
130
131
// Delete removes a key from the parsed value
132
func (v *Value) Delete(key string) bool {
133
return v.parsed.Delete(key)
134
}
135
136
// Encode encodes the value into a string
137
// using the dataformat and encoding
138
func (v *Value) Encode() (string, error) {
139
toEncodeStr := v.data
140
if v.parsed.OrderedMap != nil {
141
// flattening orderedmap not supported
142
if v.dataFormat != "" {
143
dataformatStr, err := dataformat.Encode(v.parsed, v.dataFormat)
144
if err != nil {
145
return "", err
146
}
147
toEncodeStr = dataformatStr
148
}
149
return toEncodeStr, nil
150
}
151
152
nested, err := flat.Unflatten(v.parsed.Map, flatOpts)
153
if err != nil {
154
return "", err
155
}
156
if v.dataFormat != "" {
157
dataformatStr, err := dataformat.Encode(dataformat.KVMap(nested), v.dataFormat)
158
if err != nil {
159
return "", err
160
}
161
toEncodeStr = dataformatStr
162
}
163
return toEncodeStr, nil
164
}
165
166
// In go, []int, []string are not implictily converted to []interface{}
167
// when using type assertion and they need to be handled separately.
168
func IsTypedSlice(v interface{}) ([]interface{}, bool) {
169
if reflect.ValueOf(v).Kind() == reflect.Slice {
170
// iterate and convert to []interface{}
171
slice := reflect.ValueOf(v)
172
interfaceSlice := make([]interface{}, slice.Len())
173
for i := 0; i < slice.Len(); i++ {
174
interfaceSlice[i] = slice.Index(i).Interface()
175
}
176
return interfaceSlice, true
177
}
178
return nil, false
179
}
180
181