scan error formatting (#5628)

This commit is contained in:
Tarun Koyalwar 2024-09-14 00:06:08 +05:30 committed by GitHub
parent 2ac9aaf871
commit 87e99be4f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 42 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/output" "github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs" "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/utils/errkit"
) )
type ScanContextOption func(*ScanContext) type ScanContextOption func(*ScanContext)
@ -30,7 +31,7 @@ type ScanContext struct {
OnWarning func(string) OnWarning func(string)
// unexported state fields // unexported state fields
errors []error error error
warnings []string warnings []string
events []*output.InternalWrappedEvent events []*output.InternalWrappedEvent
results []*output.ResultEvent results []*output.ResultEvent
@ -52,8 +53,8 @@ func (s *ScanContext) Context() context.Context {
return s.ctx return s.ctx
} }
func (s *ScanContext) GenerateErrorMessage() string { func (s *ScanContext) GenerateErrorMessage() error {
return joinErrors(s.errors) return s.error
} }
// GenerateResult returns final results slice from all events // GenerateResult returns final results slice from all events
@ -94,13 +95,16 @@ func (s *ScanContext) LogError(err error) {
if err == nil { if err == nil {
return return
} }
if s.OnError != nil { if s.OnError != nil {
s.OnError(err) 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 { for _, result := range s.results {
result.Error = errorMessage result.Error = errorMessage
@ -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, "; ")
}

View File

@ -20,7 +20,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto"
"github.com/projectdiscovery/nuclei/v3/pkg/types/nucleierr"
"github.com/projectdiscovery/utils/errkit" "github.com/projectdiscovery/utils/errkit"
) )
@ -207,7 +206,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
ctx.LogError(errx) ctx.LogError(errx)
if lastMatcherEvent != nil { if lastMatcherEvent != nil {
lastMatcherEvent.InternalEvent["error"] = tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())) lastMatcherEvent.InternalEvent["error"] = getErrorCause(ctx.GenerateErrorMessage())
writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus) writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus)
} }
@ -222,7 +221,7 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
Info: e.options.TemplateInfo, Info: e.options.TemplateInfo,
Type: e.getTemplateType(), Type: e.getTemplateType(),
Host: ctx.Input.MetaInput.Input, Host: ctx.Input.MetaInput.Input,
Error: tryParseCause(fmt.Errorf("%s", ctx.GenerateErrorMessage())), Error: getErrorCause(ctx.GenerateErrorMessage()),
}, },
}, },
OperatorsResult: &operators.Result{ OperatorsResult: &operators.Result{
@ -235,31 +234,27 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) {
return executed.Load() || matched.Load(), errx 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 // this is legacy support due to use of errorutil in existing libraries
// but this should not be required once all libraries are updated // but this should not be required once all libraries are updated
func tryParseCause(err error) string { func getErrorCause(err error) string {
errStr := "" if err == nil {
errX := errkit.FromError(err) return ""
if errX != nil {
var errCause error
if len(errX.Errors()) > 1 {
errCause = errX.Errors()[0]
}
if errCause == nil {
errCause = errX
}
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))
} }
errx := errkit.FromError(err)
return errStr var cause error
for _, e := range errx.Errors() {
if e != nil && strings.Contains(e.Error(), "context deadline exceeded") {
continue
}
cause = e
break
}
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. // ExecuteWithResults executes the protocol requests and returns results instead of writing them.

View File

@ -1,10 +1,15 @@
package tmplexec package tmplexec
import ( import (
"errors"
"regexp"
"strings"
"github.com/projectdiscovery/nuclei/v3/pkg/scan" "github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/flow"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/generic"
"github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto" "github.com/projectdiscovery/nuclei/v3/pkg/tmplexec/multiproto"
"github.com/projectdiscovery/utils/errkit"
) )
var ( var (
@ -30,3 +35,37 @@ type TemplateEngine interface {
// Name returns name of template engine // Name returns name of template engine
Name() string 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, "")
}