Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scan error formatting #5628

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions pkg/scan/scan_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/utils/errkit"
)

type ScanContextOption func(*ScanContext)
Expand All @@ -30,7 +31,7 @@ type ScanContext struct {
OnWarning func(string)

// unexported state fields
errors []error
error error
warnings []string
events []*output.InternalWrappedEvent
results []*output.ResultEvent
Expand All @@ -52,8 +53,8 @@ func (s *ScanContext) Context() context.Context {
return s.ctx
}

func (s *ScanContext) GenerateErrorMessage() string {
return joinErrors(s.errors)
func (s *ScanContext) GenerateErrorMessage() error {
return s.error
}

// GenerateResult returns final results slice from all events
Expand Down Expand Up @@ -94,13 +95,16 @@ func (s *ScanContext) LogError(err error) {
if err == nil {
return
}

if s.OnError != nil {
s.OnError(err)
}
s.errors = append(s.errors, err)
if s.error == nil {
s.error = err
} else {
s.error = errkit.Append(s.error, err)
}

errorMessage := s.GenerateErrorMessage()
errorMessage := s.GenerateErrorMessage().Error()

for _, result := range s.results {
result.Error = errorMessage
Expand Down Expand Up @@ -129,14 +133,3 @@ func (s *ScanContext) LogWarning(format string, args ...any) {
}
}
}

// joinErrors joins multiple errors and returns a single error string
func joinErrors(errors []error) string {
var errorMessages []string
for _, e := range errors {
if e != nil {
errorMessages = append(errorMessages, e.Error())
}
}
return strings.Join(errorMessages, "; ")
}
43 changes: 19 additions & 24 deletions pkg/tmplexec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto"
"github.com/projectdiscovery/nuclei/v3/pkg/types/nucleierr"
"github.com/projectdiscovery/utils/errkit"
)

Expand Down Expand Up @@ -207,7 +206,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
ctx.LogError(errx)

if lastMatcherEvent != nil {
lastMatcherEvent.InternalEvent["error"] = tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage()))
lastMatcherEvent.InternalEvent["error"] = getErrorCause(ctx.GenerateErrorMessage())
writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus)
}

Expand All @@ -222,7 +221,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
Info: e.options.TemplateInfo,
Type: e.getTemplateType(),
Host: ctx.Input.MetaInput.Input,
Error: tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())),
Error: getErrorCause(ctx.GenerateErrorMessage()),
},
},
OperatorsResult: &operators.Result{
Expand All @@ -235,31 +234,27 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
return executed.Load() || matched.Load(), errx
}

// tryParseCause tries to parse the cause of given error
// getErrorCause tries to parse the cause of given error
// this is legacy support due to use of errorutil in existing libraries
// but this should not be required once all libraries are updated
func tryParseCause(err error) string {
errStr := ""
errX := errkit.FromError(err)
if errX != nil {
var errCause error

if len(errX.Errors()) > 1 {
errCause = errX.Errors()[0]
}
if errCause == nil {
errCause = errX
func getErrorCause(err error) string {
if err == nil {
return ""
}
errx := errkit.FromError(err)
var cause error
for _, e := range errx.Errors() {
if e != nil && strings.Contains(e.Error(), "context deadline exceeded") {
continue
}

msg := strings.Trim(errCause.Error(), "{} ")
parts := strings.Split(msg, ":")
errCause = errkit.New("%s", parts[len(parts)-1])
errKind := errkit.GetErrorKind(err, nucleierr.ErrTemplateLogic).String()
errStr = errCause.Error()
errStr = strings.TrimSpace(strings.Replace(errStr, "errKind="+errKind, "", -1))
cause = e
break
}

return errStr
if cause == nil {
cause = errkit.Append(errkit.New("could not get error cause"), errx)
}
// parseScanError prettifies the error message and removes everything except the cause
return parseScanError(cause.Error())
}

// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
Expand Down
39 changes: 39 additions & 0 deletions pkg/tmplexec/interface.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package tmplexec

import (
"errors"
"regexp"
"strings"

"github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto"
"github.com/projectdiscovery/utils/errkit"
)

var (
Expand All @@ -30,3 +35,37 @@ type TemplateEngine interface {
// Name returns name of template engine
Name() string
}

var (
// A temporary fix to remove errKind from error message
// this is because errkit is not used everywhere yet
reNoKind = regexp.MustCompile(`([\[][^][]+[\]]|errKind=[^ ]+) `)
)

// parseScanError parses given scan error and only returning the cause
// instead of inefficient one
func parseScanError(msg string) string {
if msg == "" {
return ""
}
if strings.HasPrefix(msg, "ReadStatusLine:") {
// last index is actual error (from rawhttp)
parts := strings.Split(msg, ":")
msg = strings.TrimSpace(parts[len(parts)-1])
}
if strings.Contains(msg, "read ") {
// same here
parts := strings.Split(msg, ":")
msg = strings.TrimSpace(parts[len(parts)-1])
}
e := errkit.FromError(errors.New(msg))
for _, err := range e.Errors() {
if err != nil && strings.Contains(err.Error(), "context deadline exceeded") {
continue
}
msg = reNoKind.ReplaceAllString(err.Error(), "")
return msg
}
wrapped := errkit.Append(errkit.New("failed to get error cause"), e).Error()
return reNoKind.ReplaceAllString(wrapped, "")
}
Loading