mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-08 17:39:09 -10:00
144 lines
3.4 KiB
Go
144 lines
3.4 KiB
Go
package dataformat
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// dataformats is a list of dataformats
|
|
var dataformats map[string]DataFormat
|
|
|
|
const (
|
|
// DefaultKey is the key i.e used when given
|
|
// data is not of k-v type
|
|
DefaultKey = "value"
|
|
)
|
|
|
|
func init() {
|
|
dataformats = make(map[string]DataFormat)
|
|
|
|
// register the default data formats
|
|
RegisterDataFormat(NewGraphql())
|
|
RegisterDataFormat(NewJSON())
|
|
RegisterDataFormat(NewXML())
|
|
RegisterDataFormat(NewRaw())
|
|
RegisterDataFormat(NewForm())
|
|
RegisterDataFormat(NewMultiPartForm())
|
|
}
|
|
|
|
const (
|
|
// GraphqlDataFormat is the name of the GraphQL-over-HTTP JSON data format
|
|
GraphqlDataFormat = "graphql"
|
|
// JSONDataFormat is the name of the JSON data format
|
|
JSONDataFormat = "json"
|
|
// XMLDataFormat is the name of the XML data format
|
|
XMLDataFormat = "xml"
|
|
// RawDataFormat is the name of the Raw data format
|
|
RawDataFormat = "raw"
|
|
// FormDataFormat is the name of the Form data format
|
|
FormDataFormat = "form"
|
|
// MultiPartFormDataFormat is the name of the MultiPartForm data format
|
|
MultiPartFormDataFormat = "multipart/form-data"
|
|
)
|
|
|
|
// decodePriority prefers more specific formats before generic ones (GraphQL
|
|
// bodies are valid JSON, so GraphQL must win over JSON).
|
|
var decodePriority = []string{
|
|
GraphqlDataFormat,
|
|
JSONDataFormat,
|
|
XMLDataFormat,
|
|
MultiPartFormDataFormat,
|
|
FormDataFormat,
|
|
RawDataFormat,
|
|
}
|
|
|
|
// Get returns the dataformat by name
|
|
func Get(name string) DataFormat {
|
|
return dataformats[name]
|
|
}
|
|
|
|
// RegisterEncoder registers an encoder
|
|
func RegisterDataFormat(dataformat DataFormat) {
|
|
dataformats[dataformat.Name()] = dataformat
|
|
}
|
|
|
|
// DataFormat is an interface for encoding and decoding
|
|
type DataFormat interface {
|
|
// IsType returns true if the data is of the type
|
|
IsType(data string) bool
|
|
// Name returns the name of the encoder
|
|
Name() string
|
|
// Encode encodes the data into a format
|
|
Encode(data KV) (string, error)
|
|
// Decode decodes the data from a format
|
|
Decode(input string) (KV, error)
|
|
}
|
|
|
|
// Decoded is a decoded data format
|
|
type Decoded struct {
|
|
// DataFormat is the data format
|
|
DataFormat string
|
|
// Data is the decoded data
|
|
Data KV
|
|
}
|
|
|
|
// Decode decodes the data from a format
|
|
func Decode(data string) (*Decoded, error) {
|
|
tryDecode := func(dataformat DataFormat) (*Decoded, error) {
|
|
if dataformat == nil || !dataformat.IsType(data) {
|
|
return nil, nil
|
|
}
|
|
decoded, err := dataformat.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Decoded{
|
|
DataFormat: dataformat.Name(),
|
|
Data: decoded,
|
|
}, nil
|
|
}
|
|
|
|
for _, name := range decodePriority {
|
|
decoded, err := tryDecode(dataformats[name])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if decoded != nil {
|
|
return decoded, nil
|
|
}
|
|
}
|
|
for name, dataformat := range dataformats {
|
|
if containsString(decodePriority, name) {
|
|
continue
|
|
}
|
|
decoded, err := tryDecode(dataformat)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if decoded != nil {
|
|
return decoded, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func containsString(items []string, want string) bool {
|
|
for _, item := range items {
|
|
if item == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Encode encodes the data into a format
|
|
func Encode(data KV, dataformat string) (string, error) {
|
|
if dataformat == "" {
|
|
return "", errors.New("dataformat is required")
|
|
}
|
|
if encoder, ok := dataformats[dataformat]; ok {
|
|
return encoder.Encode(data)
|
|
}
|
|
return "", fmt.Errorf("dataformat %s is not supported", dataformat)
|
|
}
|