package fuzz
import (
"fmt"
"github.com/invopop/jsonschema"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
mapsutil "github.com/projectdiscovery/utils/maps"
"gopkg.in/yaml.v2"
)
var (
_ json.JSONCodec = &SliceOrMapSlice{}
_ yaml.Marshaler = &SliceOrMapSlice{}
_ yaml.Unmarshaler = &SliceOrMapSlice{}
)
type ValueOrKeyValue struct {
Key string
Value string
OriginalPayload string
}
func (v *ValueOrKeyValue) IsKV() bool {
return v.Key != ""
}
type SliceOrMapSlice struct {
Value []string
KV *mapsutil.OrderedMap[string, string]
}
func (v SliceOrMapSlice) JSONSchemaExtend(schema *jsonschema.Schema) *jsonschema.Schema {
schema = &jsonschema.Schema{
Title: schema.Title,
Description: schema.Description,
Type: "array",
Items: &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "object",
},
},
},
}
return schema
}
func (v SliceOrMapSlice) JSONSchema() *jsonschema.Schema {
gotType := &jsonschema.Schema{
Title: "Payloads of Fuzz Rule",
Description: "Payloads to perform fuzzing substitutions with.",
Type: "array",
Items: &jsonschema.Schema{
OneOf: []*jsonschema.Schema{
{
Type: "string",
},
{
Type: "object",
},
},
},
}
return gotType
}
func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &v.Value); err == nil {
return nil
}
err := json.Unmarshal(data, &v.KV)
if err != nil {
return fmt.Errorf("object can be a key:value or a string")
}
return nil
}
func (v SliceOrMapSlice) MarshalJSON() ([]byte, error) {
if v.KV != nil {
return json.Marshal(v.KV)
}
return json.Marshal(v.Value)
}
func (v *SliceOrMapSlice) UnmarshalYAML(callback func(interface{}) error) error {
if err := callback(&v.Value); err == nil {
return nil
}
var node yaml.MapSlice
if err := callback(&node); err == nil {
tmpx := mapsutil.NewOrderedMap[string, string]()
for _, v := range node {
tmpx.Set(v.Key.(string), v.Value.(string))
}
v.KV = &tmpx
return nil
}
return fmt.Errorf("object can be a key:value or a string")
}
func (v SliceOrMapSlice) MarshalYAML() (any, error) {
if v.KV != nil {
return v.KV, nil
}
return v.Value, nil
}