nuclei/v2/pkg/parsers/parser.go

99 lines
2.8 KiB
Go

package parsers
import (
"bytes"
"errors"
"fmt"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter"
"github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
)
const mandatoryFieldMissingTemplate = "mandatory '%s' field is missing"
// Load loads a template by parsing metadata and running
// all tag and path based filters on the template.
func Load(templatePath string, isWorkflow bool, workflowTags []string, tagFilter *filter.TagFilter) (bool, error) {
template, templateParseError := parseTemplate(templatePath)
if templateParseError != nil {
return false, templateParseError
}
templateInfo := template.Info
if validationError := validateMandatoryInfoFields(templateInfo); validationError != nil {
return false, validationError
}
if utils.IsNotEmpty(template.Workflows) {
if isWorkflow {
return true, nil // if a workflow is declared and this template is a workflow, then load
} else {
return false, nil // if a workflow is declared and this template is not a workflow then do not load
}
} else if isWorkflow {
return false, nil // if no workflows are declared and this template is a workflow then do not load
} else { // if workflows are not declared and the template is not a workflow then parse it
return isInfoMetadataMatch(tagFilter, templateInfo, workflowTags)
}
}
func isInfoMetadataMatch(tagFilter *filter.TagFilter, templateInfo model.Info, workflowTags []string) (bool, error) {
templateTags := templateInfo.Tags.ToSlice()
templateAuthors := templateInfo.Authors.ToSlice()
templateSeverity := templateInfo.SeverityHolder.Severity
var match bool
var err error
if utils.IsEmpty(workflowTags) {
match, err = tagFilter.Match(templateTags, templateAuthors, templateSeverity)
} else {
match, err = tagFilter.MatchWithWorkflowTags(templateTags, templateAuthors, templateSeverity, workflowTags)
}
if err == filter.ErrExcluded {
return false, filter.ErrExcluded
}
return match, nil
}
func validateMandatoryInfoFields(info model.Info) error {
if utils.IsEmpty(info) {
return errors.New(fmt.Sprintf(mandatoryFieldMissingTemplate, "info"))
}
if utils.IsEmpty(info.Name) {
return errors.New(fmt.Sprintf(mandatoryFieldMissingTemplate, "name"))
}
authors := info.Authors.ToSlice()
if utils.IsEmpty(authors) {
return errors.New(fmt.Sprintf(mandatoryFieldMissingTemplate, "author"))
}
return nil
}
func parseTemplate(templatePath string) (*templates.Template, error) {
f, err := os.Open(templatePath)
if err != nil {
return nil, err
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
template := &templates.Template{}
err = yaml.NewDecoder(bytes.NewReader(data)).Decode(template)
if err != nil {
return nil, err
}
return template, nil
}