mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-18 14:45:27 +00:00
Extending YAML to support include preprocessing (#1767)
* Add support for include directive * adding yamlc support * mod tidy * removing yamlc * moving code around
This commit is contained in:
parent
221cd7b6a2
commit
a19385376c
@ -5,14 +5,13 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter"
|
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates/cache"
|
"github.com/projectdiscovery/nuclei/v2/pkg/templates/cache"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
|
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
|
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||||
|
"github.com/projectdiscovery/nuclei/v2/pkg/utils/yaml"
|
||||||
|
fileutil "github.com/projectdiscovery/utils/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsBlank(value string) bool {
|
func IsBlank(value string) bool {
|
||||||
@ -27,42 +29,42 @@ func UnwrapError(err error) error {
|
|||||||
|
|
||||||
// IsURL tests a string to determine if it is a well-structured url or not.
|
// IsURL tests a string to determine if it is a well-structured url or not.
|
||||||
func IsURL(input string) bool {
|
func IsURL(input string) bool {
|
||||||
_, err := url.ParseRequestURI(input)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(input)
|
u, err := url.Parse(input)
|
||||||
if err != nil || u.Scheme == "" || u.Host == "" {
|
return err == nil && u.Scheme != "" && u.Host != ""
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFromPathOrURL reads and returns the contents of a file or url.
|
// ReadFromPathOrURL reads and returns the contents of a file or url.
|
||||||
func ReadFromPathOrURL(templatePath string, catalog catalog.Catalog) (data []byte, err error) {
|
func ReadFromPathOrURL(templatePath string, catalog catalog.Catalog) (data []byte, err error) {
|
||||||
|
var reader io.Reader
|
||||||
if IsURL(templatePath) {
|
if IsURL(templatePath) {
|
||||||
resp, err := http.Get(templatePath)
|
resp, err := http.Get(templatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
data, err = io.ReadAll(resp.Body)
|
reader = resp.Body
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
f, err := catalog.OpenFile(templatePath)
|
f, err := catalog.OpenFile(templatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
data, err = io.ReadAll(f)
|
reader = f
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err = io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-process directives only for local files
|
||||||
|
if fileutil.FileExists(templatePath) {
|
||||||
|
data, err = yaml.PreProcess(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
65
v2/pkg/utils/yaml/preprocess.go
Normal file
65
v2/pkg/utils/yaml/preprocess.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
fileutil "github.com/projectdiscovery/utils/file"
|
||||||
|
stringsutil "github.com/projectdiscovery/utils/strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var reImportsPattern = regexp.MustCompile(`(?m)# !include:(.+.yaml)`)
|
||||||
|
|
||||||
|
// PreProcess all include directives
|
||||||
|
func PreProcess(data []byte) ([]byte, error) {
|
||||||
|
// find all matches like !include:path\n
|
||||||
|
importMatches := reImportsPattern.FindAllSubmatch(data, -1)
|
||||||
|
|
||||||
|
var replaceItems []string
|
||||||
|
|
||||||
|
for _, match := range importMatches {
|
||||||
|
var (
|
||||||
|
matchString string
|
||||||
|
includeFileName string
|
||||||
|
)
|
||||||
|
matchBytes := match[0]
|
||||||
|
matchString = string(matchBytes)
|
||||||
|
if len(match) > 0 {
|
||||||
|
includeFileName = string(match[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the number of tabs/spaces between the last \n and the beginning of the match
|
||||||
|
matchIndex := bytes.Index(data, matchBytes)
|
||||||
|
lastNewLineIndex := bytes.LastIndex(data[:matchIndex], []byte("\n"))
|
||||||
|
padBytes := data[lastNewLineIndex:matchIndex]
|
||||||
|
|
||||||
|
// check if the file exists
|
||||||
|
if fileutil.FileExists(includeFileName) {
|
||||||
|
// and in case replace the comment with it
|
||||||
|
includeFileContent, err := os.ReadFile(includeFileName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// if it's yaml, tries to preprocess that too recursively
|
||||||
|
if stringsutil.HasSuffixAny(includeFileName, ".yaml") {
|
||||||
|
if subIncludedFileContent, err := PreProcess(includeFileContent); err == nil {
|
||||||
|
includeFileContent = subIncludedFileContent
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad each line of file content with padBytes
|
||||||
|
includeFileContent = bytes.ReplaceAll(includeFileContent, []byte("\n"), padBytes)
|
||||||
|
|
||||||
|
replaceItems = append(replaceItems, matchString)
|
||||||
|
replaceItems = append(replaceItems, string(includeFileContent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replacer := strings.NewReplacer(replaceItems...)
|
||||||
|
|
||||||
|
return []byte(replacer.Replace(string(data))), nil
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user