mirror of https://github.com/daffainfo/nuclei.git
fix(schema): generation of missing JSON schema definitions (#4995)
* fix(schema): generation of missing JSON schema definitions * make headers and data to accept multi-type inputs * misc updatedev
parent
82e25f6631
commit
8c27ca2591
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -33,6 +34,12 @@ func main() {
|
||||||
|
|
||||||
// Generate jsonschema
|
// Generate jsonschema
|
||||||
r := &jsonschema.Reflector{}
|
r := &jsonschema.Reflector{}
|
||||||
|
r.Namer = func(r reflect.Type) string {
|
||||||
|
if r.Kind() == reflect.Slice {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.String()
|
||||||
|
}
|
||||||
jsonschemaData := r.Reflect(&templates.Template{})
|
jsonschemaData := r.Reflect(&templates.Template{})
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/invopop/jsonschema"
|
||||||
mapsutil "github.com/projectdiscovery/utils/maps"
|
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
@ -29,6 +30,44 @@ type SliceOrMapSlice struct {
|
||||||
KV *mapsutil.OrderedMap[string, 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
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler interface.
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
||||||
func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
|
func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
|
||||||
// try to unmashal as a string and fallback to map
|
// try to unmashal as a string and fallback to map
|
||||||
|
|
|
@ -61,7 +61,7 @@ type UserAgentHolder struct {
|
||||||
Value UserAgent `mapping:"true"`
|
Value UserAgent `mapping:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (userAgentHolder UserAgentHolder) JSONSchemaType() *jsonschema.Schema {
|
func (userAgentHolder UserAgentHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "userAgent for the headless",
|
Title: "userAgent for the headless",
|
||||||
|
|
|
@ -72,7 +72,7 @@ type ExtractorTypeHolder struct {
|
||||||
ExtractorType ExtractorType `mapping:"true"`
|
ExtractorType ExtractorType `mapping:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder ExtractorTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder ExtractorTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of the extractor",
|
Title: "type of the extractor",
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (t MatcherTypeHolder) String() string {
|
||||||
return t.MatcherType.String()
|
return t.MatcherType.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder MatcherTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder MatcherTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of the matcher",
|
Title: "type of the matcher",
|
||||||
|
|
|
@ -48,25 +48,25 @@ var (
|
||||||
type Request struct {
|
type Request struct {
|
||||||
// Operators for the current request go here.
|
// Operators for the current request go here.
|
||||||
operators.Operators `yaml:",inline,omitempty"`
|
operators.Operators `yaml:",inline,omitempty"`
|
||||||
CompiledOperators *operators.Operators `yaml:"-"`
|
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
|
||||||
|
|
||||||
// ID is the optional id of the request
|
// ID is the optional id of the request
|
||||||
ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID of the Request"`
|
ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID of the Request"`
|
||||||
// description: |
|
// description: |
|
||||||
// Engine type
|
// Engine type
|
||||||
Engine []string `yaml:"engine,omitempty" jsonschema:"title=engine,description=Engine"`
|
Engine []string `yaml:"engine,omitempty" json:"engine,omitempty" jsonschema:"title=engine,description=Engine"`
|
||||||
// description: |
|
// description: |
|
||||||
// PreCondition is a condition which is evaluated before sending the request.
|
// PreCondition is a condition which is evaluated before sending the request.
|
||||||
PreCondition string `yaml:"pre-condition,omitempty" json:"pre-condition,omitempty" jsonschema:"title=pre-condition for the request,description=PreCondition is a condition which is evaluated before sending the request"`
|
PreCondition string `yaml:"pre-condition,omitempty" json:"pre-condition,omitempty" jsonschema:"title=pre-condition for the request,description=PreCondition is a condition which is evaluated before sending the request"`
|
||||||
// description: |
|
// description: |
|
||||||
// Engine Arguments
|
// Engine Arguments
|
||||||
Args []string `yaml:"args,omitempty" jsonschema:"title=args,description=Args"`
|
Args []string `yaml:"args,omitempty" json:"args,omitempty" jsonschema:"title=args,description=Args"`
|
||||||
// description: |
|
// description: |
|
||||||
// Pattern preferred for file name
|
// Pattern preferred for file name
|
||||||
Pattern string `yaml:"pattern,omitempty" jsonschema:"title=pattern,description=Pattern"`
|
Pattern string `yaml:"pattern,omitempty" json:"pattern,omitempty" jsonschema:"title=pattern,description=Pattern"`
|
||||||
// description: |
|
// description: |
|
||||||
// Source File/Snippet
|
// Source File/Snippet
|
||||||
Source string `yaml:"source,omitempty" jsonschema:"title=source file/snippet,description=Source snippet"`
|
Source string `yaml:"source,omitempty" json:"source,omitempty" jsonschema:"title=source file/snippet,description=Source snippet"`
|
||||||
|
|
||||||
options *protocols.ExecutorOptions `yaml:"-" json:"-"`
|
options *protocols.ExecutorOptions `yaml:"-" json:"-"`
|
||||||
preConditionCompiled *goja.Program `yaml:"-" json:"-"`
|
preConditionCompiled *goja.Program `yaml:"-" json:"-"`
|
||||||
|
|
|
@ -61,7 +61,7 @@ type AttackTypeHolder struct {
|
||||||
Value AttackType `mapping:"true"`
|
Value AttackType `mapping:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder AttackTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder AttackTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of the attack",
|
Title: "type of the attack",
|
||||||
|
|
|
@ -21,7 +21,7 @@ type Variable struct {
|
||||||
utils.InsertionOrderedStringMap `yaml:"-" json:"-"`
|
utils.InsertionOrderedStringMap `yaml:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (variables Variable) JSONSchemaType() *jsonschema.Schema {
|
func (variables Variable) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "object",
|
Type: "object",
|
||||||
Title: "variables for the request",
|
Title: "variables for the request",
|
||||||
|
|
|
@ -60,7 +60,7 @@ type Request struct {
|
||||||
// examples:
|
// examples:
|
||||||
// - name: Use a retry of 100 to 150 generally
|
// - name: Use a retry of 100 to 150 generally
|
||||||
// value: 100
|
// value: 100
|
||||||
TraceMaxRecursion int `yaml:"trace-max-recursion,omitempty" jsonschema:"title=trace-max-recursion level for dns request,description=TraceMaxRecursion is the number of max recursion allowed for trace operations"`
|
TraceMaxRecursion int `yaml:"trace-max-recursion,omitempty" json:"trace-max-recursion,omitempty" jsonschema:"title=trace-max-recursion level for dns request,description=TraceMaxRecursion is the number of max recursion allowed for trace operations"`
|
||||||
|
|
||||||
// description: |
|
// description: |
|
||||||
// Attack is the type of payload combinations to perform.
|
// Attack is the type of payload combinations to perform.
|
||||||
|
@ -83,7 +83,7 @@ type Request struct {
|
||||||
Threads int `yaml:"threads,omitempty" json:"threads,omitempty" jsonschema:"title=threads for sending requests,description=Threads specifies number of threads to use sending requests. This enables Connection Pooling"`
|
Threads int `yaml:"threads,omitempty" json:"threads,omitempty" jsonschema:"title=threads for sending requests,description=Threads specifies number of threads to use sending requests. This enables Connection Pooling"`
|
||||||
generator *generators.PayloadGenerator
|
generator *generators.PayloadGenerator
|
||||||
|
|
||||||
CompiledOperators *operators.Operators `yaml:"-"`
|
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
|
||||||
dnsClient *retryabledns.Client
|
dnsClient *retryabledns.Client
|
||||||
options *protocols.ExecutorOptions
|
options *protocols.ExecutorOptions
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (holder DNSRequestTypeHolder) String() string {
|
||||||
return holder.DNSRequestType.String()
|
return holder.DNSRequestType.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder DNSRequestTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder DNSRequestTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of DNS request to make",
|
Title: "type of DNS request to make",
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package engine
|
package engine
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/invopop/jsonschema"
|
||||||
|
)
|
||||||
|
|
||||||
// Action is an action taken by the browser to reach a navigation
|
// Action is an action taken by the browser to reach a navigation
|
||||||
//
|
//
|
||||||
|
@ -29,6 +33,29 @@ type Action struct {
|
||||||
ActionType ActionTypeHolder `yaml:"action" json:"action" jsonschema:"title=action to perform,description=Type of actions to perform,enum=navigate,enum=script,enum=click,enum=rightclick,enum=text,enum=screenshot,enum=time,enum=select,enum=files,enum=waitload,enum=getresource,enum=extract,enum=setmethod,enum=addheader,enum=setheader,enum=deleteheader,enum=setbody,enum=waitevent,enum=keyboard,enum=debug,enum=sleep"`
|
ActionType ActionTypeHolder `yaml:"action" json:"action" jsonschema:"title=action to perform,description=Type of actions to perform,enum=navigate,enum=script,enum=click,enum=rightclick,enum=text,enum=screenshot,enum=time,enum=select,enum=files,enum=waitload,enum=getresource,enum=extract,enum=setmethod,enum=addheader,enum=setheader,enum=deleteheader,enum=setbody,enum=waitevent,enum=keyboard,enum=debug,enum=sleep"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Action) JSONSchemaExtend(schema *jsonschema.Schema) {
|
||||||
|
argsSchema, ok := schema.Properties.Get("args")
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
argsSchema.PatternProperties = map[string]*jsonschema.Schema{
|
||||||
|
".*": {
|
||||||
|
OneOf: []*jsonschema.Schema{
|
||||||
|
{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "integer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
argsSchema.Ref = ""
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string representation of an action
|
// String returns the string representation of an action
|
||||||
func (a *Action) String() string {
|
func (a *Action) String() string {
|
||||||
builder := &strings.Builder{}
|
builder := &strings.Builder{}
|
||||||
|
|
|
@ -171,7 +171,7 @@ type ActionTypeHolder struct {
|
||||||
func (holder ActionTypeHolder) String() string {
|
func (holder ActionTypeHolder) String() string {
|
||||||
return holder.ActionType.String()
|
return holder.ActionType.String()
|
||||||
}
|
}
|
||||||
func (holder ActionTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder ActionTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "action to perform",
|
Title: "action to perform",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/invopop/jsonschema"
|
||||||
json "github.com/json-iterator/go"
|
json "github.com/json-iterator/go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
@ -219,6 +220,29 @@ type Request struct {
|
||||||
fuzzPreConditionOperator matchers.ConditionType `yaml:"-" json:"-"`
|
fuzzPreConditionOperator matchers.ConditionType `yaml:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e Request) JSONSchemaExtend(schema *jsonschema.Schema) {
|
||||||
|
headersSchema, ok := schema.Properties.Get("headers")
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headersSchema.PatternProperties = map[string]*jsonschema.Schema{
|
||||||
|
".*": {
|
||||||
|
OneOf: []*jsonschema.Schema{
|
||||||
|
{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "integer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
headersSchema.Ref = ""
|
||||||
|
}
|
||||||
|
|
||||||
// Options returns executer options for http request
|
// Options returns executer options for http request
|
||||||
func (r *Request) Options() *protocols.ExecutorOptions {
|
func (r *Request) Options() *protocols.ExecutorOptions {
|
||||||
return r.options
|
return r.options
|
||||||
|
|
|
@ -89,7 +89,7 @@ func (holder HTTPMethodTypeHolder) String() string {
|
||||||
return holder.MethodType.String()
|
return holder.MethodType.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder HTTPMethodTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder HTTPMethodTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "method is the HTTP request method",
|
Title: "method is the HTTP request method",
|
||||||
|
|
|
@ -51,7 +51,7 @@ type SignatureTypeHolder struct {
|
||||||
Value SignatureType
|
Value SignatureType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder SignatureTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder SignatureTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of the signature",
|
Title: "type of the signature",
|
||||||
|
|
|
@ -61,7 +61,7 @@ type Request struct {
|
||||||
// description: |
|
// description: |
|
||||||
// Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
|
// Port is the port to send network requests to. this acts as default port but is overriden if target/input contains
|
||||||
// non-http(s) ports like 80,8080,8081 etc
|
// non-http(s) ports like 80,8080,8081 etc
|
||||||
Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to"`
|
Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to,oneof_type=string;integer"`
|
||||||
|
|
||||||
// description: |
|
// description: |
|
||||||
// ExcludePorts is the list of ports to exclude from being scanned . It is intended to be used with `Port` field and contains a list of ports which are ignored/skipped
|
// ExcludePorts is the list of ports to exclude from being scanned . It is intended to be used with `Port` field and contains a list of ports which are ignored/skipped
|
||||||
|
@ -91,7 +91,7 @@ type Request struct {
|
||||||
|
|
||||||
// Operators for the current request go here.
|
// Operators for the current request go here.
|
||||||
operators.Operators `yaml:",inline,omitempty"`
|
operators.Operators `yaml:",inline,omitempty"`
|
||||||
CompiledOperators *operators.Operators `yaml:"-"`
|
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
|
||||||
|
|
||||||
generator *generators.PayloadGenerator
|
generator *generators.PayloadGenerator
|
||||||
// cache any variables that may be needed for operation.
|
// cache any variables that may be needed for operation.
|
||||||
|
@ -128,7 +128,7 @@ type Input struct {
|
||||||
// examples:
|
// examples:
|
||||||
// - value: "\"TEST\""
|
// - value: "\"TEST\""
|
||||||
// - value: "\"hex_decode('50494e47')\""
|
// - value: "\"hex_decode('50494e47')\""
|
||||||
Data string `yaml:"data,omitempty" json:"data,omitempty" jsonschema:"title=data to send as input,description=Data is the data to send as the input"`
|
Data string `yaml:"data,omitempty" json:"data,omitempty" jsonschema:"title=data to send as input,description=Data is the data to send as the input,oneof_type=string;integer"`
|
||||||
// description: |
|
// description: |
|
||||||
// Type is the type of input specified in `data` field.
|
// Type is the type of input specified in `data` field.
|
||||||
//
|
//
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (holder NetworkInputTypeHolder) String() string {
|
||||||
return holder.NetworkInputType.String()
|
return holder.NetworkInputType.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder NetworkInputTypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder NetworkInputTypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type is the type of input data",
|
Title: "type is the type of input data",
|
||||||
|
|
|
@ -92,7 +92,7 @@ type TypeHolder struct {
|
||||||
ProtocolType ProtocolType `mapping:"true"`
|
ProtocolType ProtocolType `mapping:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (holder TypeHolder) JSONSchemaType() *jsonschema.Schema {
|
func (holder TypeHolder) JSONSchema() *jsonschema.Schema {
|
||||||
gotType := &jsonschema.Schema{
|
gotType := &jsonschema.Schema{
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Title: "type of the protocol",
|
Title: "type of the protocol",
|
||||||
|
|
Loading…
Reference in New Issue