diff --git a/integration_tests/test-issue-tracker-config1.yaml b/integration_tests/test-issue-tracker-config1.yaml new file mode 100644 index 000000000..40594d439 --- /dev/null +++ b/integration_tests/test-issue-tracker-config1.yaml @@ -0,0 +1,68 @@ +allow-list: + severity: high, critical +deny-list: + severity: low + +# github contains configuration options for github issue tracker +#github: +# # base-url is the optional self-hosted github application url +# base-url: "" +# # username is the username of the github user +# username: "" +# # owner is the owner name of the repository for issues. +# owner: "" +# # token is the token for github account. +# token: "" +# # project-name is the name of the repository. +# project-name: "" +# # issue-label is the label of the created issue type +# issue-label: "" + +# gitlab contains configuration options for gitlab issue tracker +#gitlab: +# # base-url is the optional self-hosted gitlab application url +# base-url: "" +# # username is the username of the gitlab user +# username: "" +# # token is the token for gitlab account. +# token: "" +# # project-id is the ID of the repository. +# project-id: "" +# # issue-label is the label of the created issue type +# issue-label: "" + +# jira contains configuration options for jira issue tracker +#jira: +# # cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used +# cloud: true +# # update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created +# update-existing: false +# # URL is the jira application url +# url: "" +# # account-id is the account-id of the jira user or username in case of on-prem Jira +# account-id: "" +# # email is the email of the user for jira instance +# email: "" +# # token is the token for jira instance or password in case of on-prem Jira +# token: "" +# # project-name is the name of the project. +# project-name: "" +# # issue-type is the name of the created issue type +# issue-type: "" + +# elasticsearch contains configuration options for elasticsearch exporter +#elasticsearch: +# # IP for elasticsearch instance +# ip: 127.0.0.1 +# # Port is the port of elasticsearch instance +# port: 9200 +# # IndexName is the name of the elasticsearch index +# index-name: nuclei +# # SSL enables ssl for elasticsearch connection +# # ssl: false +# # SSLVerification disables SSL verification for elasticsearch +# # ssl-verification: false +# # Username for the elasticsearch instance +# # username: test +# # Pasword is the password for elasticsearch instance +# # password: test \ No newline at end of file diff --git a/integration_tests/test-issue-tracker-config2.yaml b/integration_tests/test-issue-tracker-config2.yaml new file mode 100644 index 000000000..633fe9d2c --- /dev/null +++ b/integration_tests/test-issue-tracker-config2.yaml @@ -0,0 +1,70 @@ +allow-list: + severity: + - high + - critical +deny-list: + severity: low + +# github contains configuration options for github issue tracker +#github: +# # base-url is the optional self-hosted github application url +# base-url: "" +# # username is the username of the github user +# username: "" +# # owner is the owner name of the repository for issues. +# owner: "" +# # token is the token for github account. +# token: "" +# # project-name is the name of the repository. +# project-name: "" +# # issue-label is the label of the created issue type +# issue-label: "" + +# gitlab contains configuration options for gitlab issue tracker +#gitlab: +# # base-url is the optional self-hosted gitlab application url +# base-url: "" +# # username is the username of the gitlab user +# username: "" +# # token is the token for gitlab account. +# token: "" +# # project-id is the ID of the repository. +# project-id: "" +# # issue-label is the label of the created issue type +# issue-label: "" + +# jira contains configuration options for jira issue tracker +#jira: +# # cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used +# cloud: true +# # update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created +# update-existing: false +# # URL is the jira application url +# url: "" +# # account-id is the account-id of the jira user or username in case of on-prem Jira +# account-id: "" +# # email is the email of the user for jira instance +# email: "" +# # token is the token for jira instance or password in case of on-prem Jira +# token: "" +# # project-name is the name of the project. +# project-name: "" +# # issue-type is the name of the created issue type +# issue-type: "" + +# elasticsearch contains configuration options for elasticsearch exporter +#elasticsearch: +# # IP for elasticsearch instance +# ip: 127.0.0.1 +# # Port is the port of elasticsearch instance +# port: 9200 +# # IndexName is the name of the elasticsearch index +# index-name: nuclei +# # SSL enables ssl for elasticsearch connection +# # ssl: false +# # SSLVerification disables SSL verification for elasticsearch +# # ssl-verification: false +# # Username for the elasticsearch instance +# # username: test +# # Pasword is the password for elasticsearch instance +# # password: test \ No newline at end of file diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go index e23d740b2..41f177d28 100644 --- a/v2/cmd/integration-test/http.go +++ b/v2/cmd/integration-test/http.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/julienschmidt/httprouter" + "github.com/projectdiscovery/nuclei/v2/internal/testutils" ) diff --git a/v2/cmd/nuclei/issue-tracker-config.yaml b/v2/cmd/nuclei/issue-tracker-config.yaml index 4664235f0..1c70b40f7 100644 --- a/v2/cmd/nuclei/issue-tracker-config.yaml +++ b/v2/cmd/nuclei/issue-tracker-config.yaml @@ -1,9 +1,9 @@ # to specify which severities should be reported #allow-list: -# severity: "critical, high" +# severity: critical, high # to specify which severities should be excluded from reporting #deny-list: -# severity: "info, low, medium" +# severity: info, low, medium # github contains configuration options for github issue tracker #github: diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go index 7bd84689b..04de3c344 100644 --- a/v2/cmd/nuclei/main.go +++ b/v2/cmd/nuclei/main.go @@ -8,7 +8,7 @@ import ( "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v2/internal/runner" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/types" ) diff --git a/v2/internal/colorizer/colorizer.go b/v2/internal/colorizer/colorizer.go index c179a0349..b43bbdb3e 100644 --- a/v2/internal/colorizer/colorizer.go +++ b/v2/internal/colorizer/colorizer.go @@ -4,8 +4,9 @@ import ( "fmt" "github.com/logrusorgru/aurora" + "github.com/projectdiscovery/gologger" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) const ( diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index cef08de9f..6a6310e51 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -19,10 +19,10 @@ import ( "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/hmap/store/hybrid" "github.com/projectdiscovery/nuclei/v2/internal/colorizer" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/parsers" "github.com/projectdiscovery/nuclei/v2/pkg/progress" @@ -87,35 +87,10 @@ func New(options *types.Options) (*Runner, error) { } runner.catalog = catalog.New(runner.options.TemplatesDirectory) - var reportingOptions *reporting.Options - if options.ReportingConfig != "" { - file, err := os.Open(options.ReportingConfig) - if err != nil { - return nil, errors.Wrap(err, "could not open reporting config file") - } - reportingOptions = &reporting.Options{} - if parseErr := yaml.NewDecoder(file).Decode(reportingOptions); parseErr != nil { - file.Close() - return nil, errors.Wrap(parseErr, "could not parse reporting config file") - } - file.Close() - } - if options.DiskExportDirectory != "" { - if reportingOptions != nil { - reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory} - } else { - reportingOptions = &reporting.Options{} - reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory} - } - } - if options.SarifExport != "" { - if reportingOptions != nil { - reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport} - } else { - reportingOptions = &reporting.Options{} - reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport} - } + reportingOptions, err := createReportingOptions(options) + if err != nil { + return nil, err } if reportingOptions != nil { client, err := reporting.New(reportingOptions, options.ReportingDB) @@ -271,6 +246,40 @@ func New(options *types.Options) (*Runner, error) { return runner, nil } +func createReportingOptions(options *types.Options) (*reporting.Options, error) { + var reportingOptions *reporting.Options + if options.ReportingConfig != "" { + file, err := os.Open(options.ReportingConfig) + if err != nil { + return nil, errors.Wrap(err, "could not open reporting config file") + } + + reportingOptions = &reporting.Options{} + if parseErr := yaml.NewDecoder(file).Decode(reportingOptions); parseErr != nil { + file.Close() + return nil, errors.Wrap(parseErr, "could not parse reporting config file") + } + file.Close() + } + if options.DiskExportDirectory != "" { + if reportingOptions != nil { + reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory} + } else { + reportingOptions = &reporting.Options{} + reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory} + } + } + if options.SarifExport != "" { + if reportingOptions != nil { + reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport} + } else { + reportingOptions = &reporting.Options{} + reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport} + } + } + return reportingOptions, nil +} + // Close releases all the resources and cleans up func (r *Runner) Close() { if r.output != nil { diff --git a/v2/internal/runner/runner_test.go b/v2/internal/runner/runner_test.go new file mode 100644 index 000000000..c057e3cd3 --- /dev/null +++ b/v2/internal/runner/runner_test.go @@ -0,0 +1,26 @@ +package runner + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/types" +) + +func Test_createReportingOptions(t *testing.T) { + var options types.Options + options.ReportingConfig = "../../../integration_tests/test-issue-tracker-config1.yaml" + resultOptions, err := createReportingOptions(&options) + + assert.Nil(t, err) + assert.Equal(t, resultOptions.AllowList.Severities, severity.Severities{severity.High, severity.Critical}) + assert.Equal(t, resultOptions.DenyList.Severities, severity.Severities{severity.Low}) + + options.ReportingConfig = "../../../integration_tests/test-issue-tracker-config2.yaml" + resultOptions2, err := createReportingOptions(&options) + assert.Nil(t, err) + assert.Equal(t, resultOptions2.AllowList.Severities, resultOptions.AllowList.Severities) + assert.Equal(t, resultOptions2.DenyList.Severities, resultOptions.DenyList.Severities) +} diff --git a/v2/internal/runner/templates.go b/v2/internal/runner/templates.go index f703adc28..8e5f8d768 100644 --- a/v2/internal/runner/templates.go +++ b/v2/internal/runner/templates.go @@ -8,7 +8,7 @@ import ( "github.com/karrick/godirwalk" "github.com/projectdiscovery/gologger" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/parsers" "github.com/projectdiscovery/nuclei/v2/pkg/types" ) diff --git a/v2/internal/severity/misc.go b/v2/internal/severity/misc.go deleted file mode 100644 index 53ecfbc3e..000000000 --- a/v2/internal/severity/misc.go +++ /dev/null @@ -1,66 +0,0 @@ -package severity - -import ( - "fmt" - "strings" -) - -type Severities []Severity - -func (severities Severities) String() string { - return strings.Join(severities.ToStringArray(), ", ") -} - -func (severities *Severities) UnmarshalYAML(unmarshal func(interface{}) error) error { - var marshalledSeverities string - if err := unmarshal(&marshalledSeverities); err != nil { - return err - } - - if err := severities.Set(marshalledSeverities); err != nil { - return err - } - return nil -} - -func (severities *Severities) Set(value string) error { - inputSeverities := toStringSlice(value) - - for _, inputSeverity := range inputSeverities { - if err := setSeverity(severities, inputSeverity); err != nil { - return err - } - } - - return nil -} - -func setSeverity(severities *Severities, value string) error { - computedSeverity, err := toSeverity(value) - if err != nil { - return fmt.Errorf("'%s' is not a valid severity", value) - } - - // TODO change the Severities type to map[Severity]interface{}, where the values are struct{}{}, to "simulates" a "set" data structure - *severities = append(*severities, computedSeverity) - return nil -} - -func (severities *Severities) ToStringArray() []string { - var result []string - for _, severity := range *severities { - result = append(result, severity.String()) - } - return result -} - -func toStringSlice(value string) []string { - var result []string - if strings.Contains(value, ",") { - slices := strings.Split(value, ",") - result = append(result, slices...) - } else { - result = []string{value} - } - return result -} diff --git a/v2/internal/severity/severity.go b/v2/internal/severity/severity.go deleted file mode 100644 index c7718e8a8..000000000 --- a/v2/internal/severity/severity.go +++ /dev/null @@ -1,95 +0,0 @@ -package severity - -import ( - "encoding/json" - "strings" - - "github.com/alecthomas/jsonschema" - "github.com/pkg/errors" -) - -type Severity int - -const ( - Undefined Severity = iota - Info - Low - Medium - High - Critical - limit -) - -var severityMappings = map[Severity]string{ - Info: "info", - Low: "low", - Medium: "medium", - High: "high", - Critical: "critical", -} - -func toSeverity(valueToMap string) (Severity, error) { - normalizedValue := normalizeValue(valueToMap) - for key, currentValue := range severityMappings { - if normalizedValue == currentValue { - return key, nil - } - } - return -1, errors.New("Invalid severity: " + valueToMap) -} - -func GetSupportedSeverities() Severities { - var result []Severity - for index := Severity(1); index < limit; index++ { - result = append(result, index) - } - return result -} - -func normalizeValue(value string) string { - return strings.TrimSpace(strings.ToLower(value)) -} - -func (severity Severity) String() string { - return severityMappings[severity] -} - -//nolint:exported,revive //prefer to be explicit about the name, and make it refactor-safe -type SeverityHolder struct { - Severity Severity -} - -func (severityHolder SeverityHolder) JSONSchemaType() *jsonschema.Type { - gotType := &jsonschema.Type{ - Type: "string", - Title: "severity of the template", - Description: "Seriousness of the implications of the template", - } - for _, severity := range GetSupportedSeverities() { - gotType.Enum = append(gotType.Enum, severity.String()) - } - return gotType -} - -func (severityHolder *SeverityHolder) UnmarshalYAML(unmarshal func(interface{}) error) error { - var marshalledSeverity string - if err := unmarshal(&marshalledSeverity); err != nil { - return err - } - - computedSeverity, err := toSeverity(marshalledSeverity) - if err != nil { - return err - } - - severityHolder.Severity = computedSeverity - return nil -} - -func (severityHolder *SeverityHolder) MarshalJSON() ([]byte, error) { - return json.Marshal(severityHolder.Severity.String()) -} - -func (severityHolder SeverityHolder) MarshalYAML() (interface{}, error) { - return severityHolder.Severity.String(), nil -} diff --git a/v2/internal/testutils/testutils.go b/v2/internal/testutils/testutils.go index 1650a1e80..d62b1d630 100644 --- a/v2/internal/testutils/testutils.go +++ b/v2/internal/testutils/testutils.go @@ -2,16 +2,17 @@ package testutils import ( "github.com/logrusorgru/aurora" + "go.uber.org/ratelimit" + "github.com/projectdiscovery/gologger/levels" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/progress" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" "github.com/projectdiscovery/nuclei/v2/pkg/types" - "go.uber.org/ratelimit" ) // Init initializes the protocols and their configurations diff --git a/v2/pkg/catalog/loader/filter/tag_filter.go b/v2/pkg/catalog/loader/filter/tag_filter.go index 90f9a8de2..7a6b7e144 100644 --- a/v2/pkg/catalog/loader/filter/tag_filter.go +++ b/v2/pkg/catalog/loader/filter/tag_filter.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) // TagFilter is used to filter nuclei templates for tag based execution diff --git a/v2/pkg/catalog/loader/filter/tag_filter_test.go b/v2/pkg/catalog/loader/filter/tag_filter_test.go index 99c6df5a6..8acc9a356 100644 --- a/v2/pkg/catalog/loader/filter/tag_filter_test.go +++ b/v2/pkg/catalog/loader/filter/tag_filter_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestTagBasedFilter(t *testing.T) { diff --git a/v2/pkg/catalog/loader/loader.go b/v2/pkg/catalog/loader/loader.go index 56feafd9e..f754513c1 100644 --- a/v2/pkg/catalog/loader/loader.go +++ b/v2/pkg/catalog/loader/loader.go @@ -4,9 +4,9 @@ import ( "errors" "github.com/projectdiscovery/gologger" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/parsers" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/templates" diff --git a/v2/pkg/model/model.go b/v2/pkg/model/model.go index 46f426646..838cc0858 100644 --- a/v2/pkg/model/model.go +++ b/v2/pkg/model/model.go @@ -1,13 +1,8 @@ package model import ( - "encoding/json" - "fmt" - "strings" - - "github.com/alecthomas/jsonschema" - "github.com/projectdiscovery/nuclei/v2/internal/severity" - "github.com/projectdiscovery/nuclei/v2/pkg/utils" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" ) // Info contains metadata information about a template @@ -25,7 +20,7 @@ type Info struct { // Multiple values can also be specified separated by commas. // examples: // - value: "\"\"" - Authors StringSlice `json:"author,omitempty" yaml:"author,omitempty" jsonschema:"title=author of the template,description=Author is the author of the template,example=username"` + Authors stringslice.StringSlice `json:"author,omitempty" yaml:"author,omitempty" jsonschema:"title=author of the template,description=Author is the author of the template,example=username"` // description: | // Any tags for the template. // @@ -34,7 +29,7 @@ type Info struct { // examples: // - name: Example tags // value: "\"cve,cve2019,grafana,auth-bypass,dos\"" - Tags StringSlice `json:"tags,omitempty" yaml:"tags,omitempty" jsonschema:"title=tags of the template,description=Any tags for the template"` + Tags stringslice.StringSlice `json:"tags,omitempty" yaml:"tags,omitempty" jsonschema:"title=tags of the template,description=Any tags for the template"` // description: | // Description of the template. // @@ -52,7 +47,7 @@ type Info struct { // examples: // - value: > // []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"} - Reference StringSlice `json:"reference,omitempty" yaml:"reference,omitempty" jsonschema:"title=references for the template,description=Links relevant to the template"` + Reference stringslice.StringSlice `json:"reference,omitempty" yaml:"reference,omitempty" jsonschema:"title=references for the template,description=Links relevant to the template"` // description: | // Severity of the template. // @@ -62,7 +57,7 @@ type Info struct { // - medium // - high // - critical - SeverityHolder severity.SeverityHolder `json:"severity,omitempty" yaml:"severity,omitempty"` + SeverityHolder severity.Holder `json:"severity,omitempty" yaml:"severity,omitempty"` // description: | // AdditionalFields regarding metadata of the template. // @@ -71,84 +66,3 @@ type Info struct { // map[string]string{"customField1":"customValue1"} AdditionalFields map[string]string `json:"additional-fields,omitempty" yaml:"additional-fields,omitempty" jsonschema:"title=additional metadata for the template,description=Additional metadata fields for the template"` } - -// StringSlice represents a single (in-lined) or multiple string value(s). -// The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required. -type StringSlice struct { - Value interface{} -} - -func (stringSlice StringSlice) JSONSchemaType() *jsonschema.Type { - gotType := &jsonschema.Type{ - OneOf: []*jsonschema.Type{{Type: "string"}, {Type: "array"}}, - } - return gotType -} - -func (stringSlice *StringSlice) IsEmpty() bool { - return len(stringSlice.ToSlice()) == 0 -} - -func (stringSlice StringSlice) ToSlice() []string { - switch value := stringSlice.Value.(type) { - case string: - return []string{value} - case []string: - return value - case nil: - return []string{} - default: - panic(fmt.Sprintf("Unexpected StringSlice type: '%T'", value)) - } -} - -func (stringSlice StringSlice) String() string { - return strings.Join(stringSlice.ToSlice(), ", ") -} - -func (stringSlice *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { - marshalledSlice, err := marshalStringToSlice(unmarshal) - if err != nil { - return err - } - - result := make([]string, 0, len(marshalledSlice)) - //nolint:gosimple,nolintlint //cannot be replaced with result = append(result, slices...) because the values are being normalized - for _, value := range marshalledSlice { - result = append(result, strings.ToLower(strings.TrimSpace(value))) // TODO do we need to introduce RawStringSlice and/or NormalizedStringSlices? - } - stringSlice.Value = result - return nil -} - -func marshalStringToSlice(unmarshal func(interface{}) error) ([]string, error) { - var marshalledValueAsString string - var marshalledValuesAsSlice []string - - sliceMarshalError := unmarshal(&marshalledValuesAsSlice) - if sliceMarshalError != nil { - stringMarshalError := unmarshal(&marshalledValueAsString) - if stringMarshalError != nil { - return nil, stringMarshalError - } - } - - var result []string - if len(marshalledValuesAsSlice) > 0 { - result = marshalledValuesAsSlice - } else if utils.IsNotBlank(marshalledValueAsString) { - result = strings.Split(marshalledValueAsString, ",") - } else { - result = []string{} - } - - return result, nil -} - -func (stringSlice StringSlice) MarshalYAML() (interface{}, error) { - return stringSlice.Value, nil -} - -func (stringSlice StringSlice) MarshalJSON() ([]byte, error) { - return json.Marshal(stringSlice.Value) -} diff --git a/v2/pkg/model/model_test.go b/v2/pkg/model/model_test.go index fc5f25a7c..120e56b55 100644 --- a/v2/pkg/model/model_test.go +++ b/v2/pkg/model/model_test.go @@ -5,20 +5,22 @@ import ( "strings" "testing" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" + "gopkg.in/yaml.v2" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/stretchr/testify/assert" ) func TestInfoJsonMarshal(t *testing.T) { info := Info{ Name: "Test Template Name", - Authors: StringSlice{[]string{"forgedhallpass", "ice3man"}}, + Authors: stringslice.StringSlice{Value: []string{"forgedhallpass", "ice3man"}}, Description: "Test description", - SeverityHolder: severity.SeverityHolder{Severity: severity.High}, - Tags: StringSlice{[]string{"cve", "misc"}}, - Reference: StringSlice{"reference1"}, + SeverityHolder: severity.Holder{Severity: severity.High}, + Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, + Reference: stringslice.StringSlice{Value: "reference1"}, } result, err := json.Marshal(&info) @@ -31,11 +33,11 @@ func TestInfoJsonMarshal(t *testing.T) { func TestInfoYamlMarshal(t *testing.T) { info := Info{ Name: "Test Template Name", - Authors: StringSlice{[]string{"forgedhallpass", "ice3man"}}, + Authors: stringslice.StringSlice{Value: []string{"forgedhallpass", "ice3man"}}, Description: "Test description", - SeverityHolder: severity.SeverityHolder{Severity: severity.High}, - Tags: StringSlice{[]string{"cve", "misc"}}, - Reference: StringSlice{"reference1"}, + SeverityHolder: severity.Holder{Severity: severity.High}, + Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, + Reference: stringslice.StringSlice{Value: "reference1"}, } result, err := yaml.Marshal(&info) diff --git a/v2/pkg/model/types/severity/severities.go b/v2/pkg/model/types/severity/severities.go new file mode 100644 index 000000000..9e3244859 --- /dev/null +++ b/v2/pkg/model/types/severity/severities.go @@ -0,0 +1,62 @@ +package severity + +import ( + "fmt" + "strings" + + "github.com/projectdiscovery/goflags" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" +) + +// Severities used by the goflags library for parsing an array of Severity types, passed as CLI arguments from the user +type Severities []Severity + +func (severities *Severities) Set(values string) error { + inputSeverities, err := goflags.ToNormalizedStringSlice(values) + if err != nil { + return err + } + + for _, inputSeverity := range inputSeverities { + if err := setSeverity(severities, inputSeverity); err != nil { + return err + } + } + return nil +} + +func (severities *Severities) UnmarshalYAML(unmarshal func(interface{}) error) error { + var stringSliceValue stringslice.StringSlice + if err := unmarshal(&stringSliceValue); err != nil { + return err + } + + stringSLice := stringSliceValue.ToSlice() + var result = make(Severities, 0, len(stringSLice)) + for _, severityString := range stringSLice { + if err := setSeverity(&result, severityString); err != nil { + return err + } + } + *severities = result + return nil +} + +func (severities Severities) String() string { + var stringSeverities []string + for _, severity := range severities { + stringSeverities = append(stringSeverities, severity.String()) + } + return strings.Join(stringSeverities, ", ") +} + +func setSeverity(severities *Severities, value string) error { + computedSeverity, err := toSeverity(value) + if err != nil { + return fmt.Errorf("'%s' is not a valid severity", value) + } + + // TODO change the Severities type to map[Severity]interface{}, where the values are struct{}{}, to "simulates" a "set" data structure + *severities = append(*severities, computedSeverity) + return nil +} diff --git a/v2/pkg/model/types/severity/severity.go b/v2/pkg/model/types/severity/severity.go new file mode 100644 index 000000000..bb52a2eb7 --- /dev/null +++ b/v2/pkg/model/types/severity/severity.go @@ -0,0 +1,53 @@ +package severity + +import ( + "strings" + + "github.com/pkg/errors" +) + +type Severity int + +const ( + Undefined Severity = iota + Info + Low + Medium + High + Critical + limit +) + +var severityMappings = map[Severity]string{ + Info: "info", + Low: "low", + Medium: "medium", + High: "high", + Critical: "critical", +} + +func GetSupportedSeverities() Severities { + var result []Severity + for index := Severity(1); index < limit; index++ { + result = append(result, index) + } + return result +} + +func toSeverity(valueToMap string) (Severity, error) { + normalizedValue := normalizeValue(valueToMap) + for key, currentValue := range severityMappings { + if normalizedValue == currentValue { + return key, nil + } + } + return -1, errors.New("Invalid severity: " + valueToMap) +} + +func normalizeValue(value string) string { + return strings.TrimSpace(strings.ToLower(value)) +} + +func (severity Severity) String() string { + return severityMappings[severity] +} diff --git a/v2/pkg/model/types/severity/severity_holder.go b/v2/pkg/model/types/severity/severity_holder.go new file mode 100644 index 000000000..ad4c2496d --- /dev/null +++ b/v2/pkg/model/types/severity/severity_holder.go @@ -0,0 +1,48 @@ +package severity + +import ( + "encoding/json" + + "github.com/alecthomas/jsonschema" +) + +//nolint:exported,revive //prefer to be explicit about the name, and make it refactor-safe +// Holder holds a Severity type. Required for un/marshalling purposes +type Holder struct { + Severity Severity +} + +func (severityHolder Holder) JSONSchemaType() *jsonschema.Type { + gotType := &jsonschema.Type{ + Type: "string", + Title: "severity of the template", + Description: "Seriousness of the implications of the template", + } + for _, severity := range GetSupportedSeverities() { + gotType.Enum = append(gotType.Enum, severity.String()) + } + return gotType +} + +func (severityHolder *Holder) UnmarshalYAML(unmarshal func(interface{}) error) error { + var marshalledSeverity string + if err := unmarshal(&marshalledSeverity); err != nil { + return err + } + + computedSeverity, err := toSeverity(marshalledSeverity) + if err != nil { + return err + } + + severityHolder.Severity = computedSeverity + return nil +} + +func (severityHolder *Holder) MarshalJSON() ([]byte, error) { + return json.Marshal(severityHolder.Severity.String()) +} + +func (severityHolder Holder) MarshalYAML() (interface{}, error) { + return severityHolder.Severity.String(), nil +} diff --git a/v2/internal/severity/severity_test.go b/v2/pkg/model/types/severity/severity_test.go similarity index 93% rename from v2/internal/severity/severity_test.go rename to v2/pkg/model/types/severity/severity_test.go index fae84ef12..b21f57265 100644 --- a/v2/internal/severity/severity_test.go +++ b/v2/pkg/model/types/severity/severity_test.go @@ -13,7 +13,7 @@ func TestYamlUnmarshal(t *testing.T) { } func TestYamlMarshal(t *testing.T) { - severity := SeverityHolder{Severity: High} + severity := Holder{Severity: High} marshalled, err := severity.MarshalYAML() assert.Nil(t, err, "could not marshal yaml") @@ -51,8 +51,8 @@ func testUnmarshalFail(t *testing.T, unmarshaller func(data []byte, v interface{ assert.Panics(t, func() { unmarshal(payloadCreator("invalid"), unmarshaller) }) } -func unmarshal(value string, unmarshaller func(data []byte, v interface{}) error) SeverityHolder { - severityStruct := SeverityHolder{} +func unmarshal(value string, unmarshaller func(data []byte, v interface{}) error) Holder { + severityStruct := Holder{} var err = unmarshaller([]byte(value), &severityStruct) if err != nil { panic(err) diff --git a/v2/pkg/model/types/stringslice/stringslice.go b/v2/pkg/model/types/stringslice/stringslice.go new file mode 100644 index 000000000..4a3e28486 --- /dev/null +++ b/v2/pkg/model/types/stringslice/stringslice.go @@ -0,0 +1,92 @@ +package stringslice + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/alecthomas/jsonschema" + + "github.com/projectdiscovery/nuclei/v2/pkg/utils" +) + +// StringSlice represents a single (in-lined) or multiple string value(s). +// The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required. +type StringSlice struct { + Value interface{} +} + +func (stringSlice StringSlice) JSONSchemaType() *jsonschema.Type { + gotType := &jsonschema.Type{ + OneOf: []*jsonschema.Type{{Type: "string"}, {Type: "array"}}, + } + return gotType +} + +func (stringSlice *StringSlice) IsEmpty() bool { + return len(stringSlice.ToSlice()) == 0 +} + +func (stringSlice StringSlice) ToSlice() []string { + switch value := stringSlice.Value.(type) { + case string: + return []string{value} + case []string: + return value + case nil: + return []string{} + default: + panic(fmt.Sprintf("Unexpected StringSlice type: '%T'", value)) + } +} + +func (stringSlice StringSlice) String() string { + return strings.Join(stringSlice.ToSlice(), ", ") +} + +func (stringSlice *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { + marshalledSlice, err := marshalStringToSlice(unmarshal) + if err != nil { + return err + } + + result := make([]string, 0, len(marshalledSlice)) + //nolint:gosimple,nolintlint //cannot be replaced with result = append(result, slices...) because the values are being normalized + for _, value := range marshalledSlice { + result = append(result, strings.ToLower(strings.TrimSpace(value))) // TODO do we need to introduce RawStringSlice and/or NormalizedStringSlices? + } + stringSlice.Value = result + return nil +} + +func (stringSlice StringSlice) MarshalYAML() (interface{}, error) { + return stringSlice.Value, nil +} + +func (stringSlice StringSlice) MarshalJSON() ([]byte, error) { + return json.Marshal(stringSlice.Value) +} + +func marshalStringToSlice(unmarshal func(interface{}) error) ([]string, error) { + var marshalledValueAsString string + var marshalledValuesAsSlice []string + + sliceMarshalError := unmarshal(&marshalledValuesAsSlice) + if sliceMarshalError != nil { + stringMarshalError := unmarshal(&marshalledValueAsString) + if stringMarshalError != nil { + return nil, stringMarshalError + } + } + + var result []string + if len(marshalledValuesAsSlice) > 0 { + result = marshalledValuesAsSlice + } else if utils.IsNotBlank(marshalledValueAsString) { + result = strings.Split(marshalledValueAsString, ",") + } else { + result = []string{} + } + + return result, nil +} diff --git a/v2/pkg/output/output.go b/v2/pkg/output/output.go index fbe3767ee..7005a9ce4 100644 --- a/v2/pkg/output/output.go +++ b/v2/pkg/output/output.go @@ -13,8 +13,8 @@ import ( "github.com/projectdiscovery/interactsh/pkg/server" "github.com/projectdiscovery/nuclei/v2/internal/colorizer" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" ) diff --git a/v2/pkg/protocols/dns/dns_test.go b/v2/pkg/protocols/dns/dns_test.go index 6e6911a5c..ae287984d 100644 --- a/v2/pkg/protocols/dns/dns_test.go +++ b/v2/pkg/protocols/dns/dns_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestDNSCompileMake(t *testing.T) { @@ -25,7 +25,7 @@ func TestDNSCompileMake(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") diff --git a/v2/pkg/protocols/dns/operators_test.go b/v2/pkg/protocols/dns/operators_test.go index c0937b91e..286dd582f 100644 --- a/v2/pkg/protocols/dns/operators_test.go +++ b/v2/pkg/protocols/dns/operators_test.go @@ -8,9 +8,9 @@ import ( "github.com/miekg/dns" "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -32,7 +32,7 @@ func TestResponseToDSLMap(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") @@ -64,7 +64,7 @@ func TestDNSOperatorMatch(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") @@ -147,7 +147,7 @@ func TestDNSOperatorExtract(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") @@ -217,7 +217,7 @@ func TestDNSMakeResult(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") diff --git a/v2/pkg/protocols/dns/request_test.go b/v2/pkg/protocols/dns/request_test.go index ee3bd3057..c77bffaed 100644 --- a/v2/pkg/protocols/dns/request_test.go +++ b/v2/pkg/protocols/dns/request_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -42,7 +42,7 @@ func TestDNSExecuteWithResults(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile dns request") diff --git a/v2/pkg/protocols/file/file_test.go b/v2/pkg/protocols/file/file_test.go index 04a1077d8..7338e1461 100644 --- a/v2/pkg/protocols/file/file_test.go +++ b/v2/pkg/protocols/file/file_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestFileCompile(t *testing.T) { @@ -24,7 +24,7 @@ func TestFileCompile(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/file/find_test.go b/v2/pkg/protocols/file/find_test.go index 0b968bc85..a2e2e9f36 100644 --- a/v2/pkg/protocols/file/find_test.go +++ b/v2/pkg/protocols/file/find_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestFindInputPaths(t *testing.T) { @@ -27,7 +27,7 @@ func TestFindInputPaths(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/file/operators_test.go b/v2/pkg/protocols/file/operators_test.go index ceb60116b..7c5be06d9 100644 --- a/v2/pkg/protocols/file/operators_test.go +++ b/v2/pkg/protocols/file/operators_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -28,7 +28,7 @@ func TestResponseToDSLMap(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -53,7 +53,7 @@ func TestFileOperatorMatch(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -118,7 +118,7 @@ func TestFileOperatorExtract(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -183,7 +183,7 @@ func TestFileMakeResult(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/file/request_test.go b/v2/pkg/protocols/file/request_test.go index b095e4cdc..0c9f7e9cc 100644 --- a/v2/pkg/protocols/file/request_test.go +++ b/v2/pkg/protocols/file/request_test.go @@ -6,14 +6,15 @@ import ( "path/filepath" "testing" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/stretchr/testify/require" + "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" "github.com/projectdiscovery/nuclei/v2/pkg/output" - "github.com/stretchr/testify/require" ) func TestFileExecuteWithResults(t *testing.T) { @@ -43,7 +44,7 @@ func TestFileExecuteWithResults(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/http/build_request_test.go b/v2/pkg/protocols/http/build_request_test.go index 43165e38c..d45f7f8f2 100644 --- a/v2/pkg/protocols/http/build_request_test.go +++ b/v2/pkg/protocols/http/build_request_test.go @@ -4,10 +4,11 @@ import ( "net/url" "testing" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/stretchr/testify/require" + "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" - "github.com/stretchr/testify/require" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestBaseURLWithTemplatePrefs(t *testing.T) { @@ -77,7 +78,7 @@ func TestMakeRequestFromModal(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile http request") @@ -104,7 +105,7 @@ func TestMakeRequestFromModalTrimSuffixSlash(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile http request") @@ -142,7 +143,7 @@ Accept-Encoding: gzip`}, } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile http request") @@ -181,7 +182,7 @@ Accept-Encoding: gzip`}, } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile http request") diff --git a/v2/pkg/protocols/http/http_test.go b/v2/pkg/protocols/http/http_test.go index 34df912b6..5f0e304b8 100644 --- a/v2/pkg/protocols/http/http_test.go +++ b/v2/pkg/protocols/http/http_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestHTTPCompile(t *testing.T) { @@ -32,7 +32,7 @@ Accept-Encoding: gzip`}, } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile http request") diff --git a/v2/pkg/protocols/http/httpclientpool/clientpool.go b/v2/pkg/protocols/http/httpclientpool/clientpool.go index 63b1479bd..1edbc5fe4 100644 --- a/v2/pkg/protocols/http/httpclientpool/clientpool.go +++ b/v2/pkg/protocols/http/httpclientpool/clientpool.go @@ -14,13 +14,14 @@ import ( "time" "github.com/pkg/errors" + "golang.org/x/net/proxy" + "golang.org/x/net/publicsuffix" + "github.com/projectdiscovery/fastdialer/fastdialer" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate" "github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/rawhttp" "github.com/projectdiscovery/retryablehttp-go" - "golang.org/x/net/proxy" - "golang.org/x/net/publicsuffix" ) var ( diff --git a/v2/pkg/protocols/http/operators_test.go b/v2/pkg/protocols/http/operators_test.go index bccb46159..6c24f236a 100644 --- a/v2/pkg/protocols/http/operators_test.go +++ b/v2/pkg/protocols/http/operators_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -29,7 +29,7 @@ func TestResponseToDSLMap(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -59,7 +59,7 @@ func TestHTTPOperatorMatch(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -129,7 +129,7 @@ func TestHTTPOperatorExtract(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -240,7 +240,7 @@ func TestHTTPMakeResult(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/network/network_test.go b/v2/pkg/protocols/network/network_test.go index ef21b28b2..180b34192 100644 --- a/v2/pkg/protocols/network/network_test.go +++ b/v2/pkg/protocols/network/network_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) func TestNetworkCompileMake(t *testing.T) { @@ -23,7 +23,7 @@ func TestNetworkCompileMake(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") diff --git a/v2/pkg/protocols/network/operators_test.go b/v2/pkg/protocols/network/operators_test.go index 36f384ba2..4c8ea3028 100644 --- a/v2/pkg/protocols/network/operators_test.go +++ b/v2/pkg/protocols/network/operators_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -27,7 +27,7 @@ func TestResponseToDSLMap(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") @@ -52,7 +52,7 @@ func TestNetworkOperatorMatch(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") @@ -115,7 +115,7 @@ func TestNetworkOperatorExtract(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") @@ -178,7 +178,7 @@ func TestNetworkMakeResult(t *testing.T) { } executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err := request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") diff --git a/v2/pkg/protocols/network/request_test.go b/v2/pkg/protocols/network/request_test.go index 5db22af54..d1f266b48 100644 --- a/v2/pkg/protocols/network/request_test.go +++ b/v2/pkg/protocols/network/request_test.go @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -55,7 +55,7 @@ func TestNetworkExecuteWithResults(t *testing.T) { request.Inputs = append(request.Inputs, &Input{Data: fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", parsed.Host)}) executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) err = request.Compile(executerOpts) require.Nil(t, err, "could not compile network request") diff --git a/v2/pkg/protocols/offlinehttp/find_test.go b/v2/pkg/protocols/offlinehttp/find_test.go index d8c1e6c22..369ef4405 100644 --- a/v2/pkg/protocols/offlinehttp/find_test.go +++ b/v2/pkg/protocols/offlinehttp/find_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" ) @@ -22,7 +22,7 @@ func TestFindResponses(t *testing.T) { request := &Request{} executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) diff --git a/v2/pkg/protocols/offlinehttp/operators_test.go b/v2/pkg/protocols/offlinehttp/operators_test.go index 980de53cb..56facee78 100644 --- a/v2/pkg/protocols/offlinehttp/operators_test.go +++ b/v2/pkg/protocols/offlinehttp/operators_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/internal/testutils" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -24,7 +24,7 @@ func TestResponseToDSLMap(t *testing.T) { request := &Request{} executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) @@ -50,7 +50,7 @@ func TestHTTPOperatorMatch(t *testing.T) { request := &Request{} executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) @@ -116,7 +116,7 @@ func TestHTTPOperatorExtract(t *testing.T) { request := &Request{} executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) @@ -169,7 +169,7 @@ func TestHTTPMakeResult(t *testing.T) { request := &Request{} executerOpts := testutils.NewMockExecuterOptions(options, &testutils.TemplateInfo{ ID: templateID, - Info: model.Info{SeverityHolder: severity.SeverityHolder{Severity: severity.Low}, Name: "test"}, + Info: model.Info{SeverityHolder: severity.Holder{Severity: severity.Low}, Name: "test"}, }) executerOpts.Operators = []*operators.Operators{{ Matchers: []*matchers.Matcher{{ diff --git a/v2/pkg/reporting/exporters/sarif/sarif.go b/v2/pkg/reporting/exporters/sarif/sarif.go index 50fdaa4e7..9c69dda3e 100644 --- a/v2/pkg/reporting/exporters/sarif/sarif.go +++ b/v2/pkg/reporting/exporters/sarif/sarif.go @@ -11,7 +11,7 @@ import ( "github.com/owenrumney/go-sarif/sarif" "github.com/pkg/errors" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/reporting/format" "github.com/projectdiscovery/nuclei/v2/pkg/utils" diff --git a/v2/pkg/reporting/format/format_test.go b/v2/pkg/reporting/format/format_test.go index a6af3d3dd..dd0899edb 100644 --- a/v2/pkg/reporting/format/format_test.go +++ b/v2/pkg/reporting/format/format_test.go @@ -6,18 +6,19 @@ import ( "github.com/stretchr/testify/assert" - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" ) func TestToMarkdownTableString(t *testing.T) { info := model.Info{ Name: "Test Template Name", - Authors: model.StringSlice{Value: []string{"forgedhallpass", "ice3man"}}, + Authors: stringslice.StringSlice{Value: []string{"forgedhallpass", "ice3man"}}, Description: "Test description", - SeverityHolder: severity.SeverityHolder{Severity: severity.High}, - Tags: model.StringSlice{Value: []string{"cve", "misc"}}, - Reference: model.StringSlice{Value: "reference1"}, + SeverityHolder: severity.Holder{Severity: severity.High}, + Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, + Reference: stringslice.StringSlice{Value: "reference1"}, AdditionalFields: map[string]string{ "customDynamicKey1": "customDynamicValue1", "customDynamicKey2": "customDynamicValue2", diff --git a/v2/pkg/reporting/reporting.go b/v2/pkg/reporting/reporting.go index 974e3e2cd..e50ec90e0 100644 --- a/v2/pkg/reporting/reporting.go +++ b/v2/pkg/reporting/reporting.go @@ -6,8 +6,8 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" - "github.com/projectdiscovery/nuclei/v2/internal/severity" - "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/reporting/dedupe" "github.com/projectdiscovery/nuclei/v2/pkg/reporting/exporters/disk" @@ -41,8 +41,8 @@ type Options struct { // Filter filters the received event and decides whether to perform // reporting for it or not. type Filter struct { - Severities severity.Severities `yaml:"severity"` - Tags model.StringSlice `yaml:"tags"` + Severities severity.Severities `yaml:"severity"` + Tags stringslice.StringSlice `yaml:"tags"` } // GetMatch returns true if a filter matches result event diff --git a/v2/pkg/templates/templates_doc.go b/v2/pkg/templates/templates_doc.go index 1a715176d..dcbc37f5a 100644 --- a/v2/pkg/templates/templates_doc.go +++ b/v2/pkg/templates/templates_doc.go @@ -1,3 +1,4 @@ +// Package templates // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/v2/pkg/templates/templates_doc_examples.go b/v2/pkg/templates/templates_doc_examples.go index 6f13cea3d..84580ffe4 100644 --- a/v2/pkg/templates/templates_doc_examples.go +++ b/v2/pkg/templates/templates_doc_examples.go @@ -1,9 +1,11 @@ +// Package templates //nolint //do not lint as examples with no usage package templates import ( - "github.com/projectdiscovery/nuclei/v2/internal/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -16,10 +18,10 @@ import ( var ( exampleInfoStructure = model.Info{ Name: "Argument Injection in Ruby Dragonfly", - Authors: model.StringSlice{"0xspara"}, - SeverityHolder: severity.SeverityHolder{severity.High}, - Reference: model.StringSlice{"https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/"}, - Tags: model.StringSlice{"cve,cve2021,rce,ruby"}, + Authors: stringslice.StringSlice{Value: "0xspara"}, + SeverityHolder: severity.Holder{Severity: severity.High}, + Reference: stringslice.StringSlice{Value: "https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/"}, + Tags: stringslice.StringSlice{Value: "cve,cve2021,rce,ruby"}, } exampleNormalHTTPRequest = &http.Request{ Method: "GET", diff --git a/v2/pkg/types/interfaces.go b/v2/pkg/types/interfaces.go index 54cf8d955..b92064dcb 100644 --- a/v2/pkg/types/interfaces.go +++ b/v2/pkg/types/interfaces.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) // JSONScalarToString converts an interface coming from json to string @@ -62,7 +62,7 @@ func ToString(data interface{}) string { return strconv.FormatUint(uint64(s), 10) case []byte: return string(s) - case severity.SeverityHolder: + case severity.Holder: return s.Severity.String() case severity.Severity: return s.String() diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go index d10199ff1..d35bbbc8d 100644 --- a/v2/pkg/types/types.go +++ b/v2/pkg/types/types.go @@ -2,7 +2,7 @@ package types import ( "github.com/projectdiscovery/goflags" - "github.com/projectdiscovery/nuclei/v2/internal/severity" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" ) // Options contains the configuration options for nuclei scanner. diff --git a/v2/pkg/workflows/workflows.go b/v2/pkg/workflows/workflows.go index fb53948fe..0e5fae34e 100644 --- a/v2/pkg/workflows/workflows.go +++ b/v2/pkg/workflows/workflows.go @@ -1,7 +1,7 @@ package workflows import ( - "github.com/projectdiscovery/nuclei/v2/pkg/model" + "github.com/projectdiscovery/nuclei/v2/pkg/model/types/stringslice" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" ) @@ -26,7 +26,7 @@ type WorkflowTemplate struct { Template string `yaml:"template,omitempty" jsonschema:"title=template/directory to execute,description=Template or directory to execute as part of workflow"` // description: | // Tags to run templates based on. - Tags model.StringSlice `yaml:"tags,omitempty" jsonschema:"title=tags to execute,description=Tags to run template based on"` + Tags stringslice.StringSlice `yaml:"tags,omitempty" jsonschema:"title=tags to execute,description=Tags to run template based on"` // description: | // Matchers perform name based matching to run subtemplates for a workflow. Matchers []*Matcher `yaml:"matchers,omitempty" jsonschema:"title=name based template result matchers,description=Matchers perform name based matching to run subtemplates for a workflow"`