mirror of https://github.com/daffainfo/nuclei.git
added custom config flag (#2399)
* added custom config flag * config.yaml file in custom directory * lint error fix * few updates and error checks * fix lint error * copy config.yaml file if the dest folder does not exist * lint error check * added integration test * improved test cases * lint error fixdev
parent
606c361b2a
commit
0aac36a44b
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
type customConfigDirTest struct{}
|
||||
|
||||
var customConfigDirTestCases = map[string]testutils.TestCase{
|
||||
"dns/cname-fingerprint.yaml": &customConfigDirTest{},
|
||||
}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *customConfigDirTest) Execute(filePath string) error {
|
||||
customTempDirectory, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(customTempDirectory)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "8x8exch02.8x8.com", debug, "-config-directory", customTempDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
files, err := os.ReadDir(customTempDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var fileNames []string
|
||||
for _, file := range files {
|
||||
fileNames = append(fileNames, file.Name())
|
||||
}
|
||||
return expectResultsCount(fileNames, 3)
|
||||
}
|
|
@ -19,20 +19,21 @@ var (
|
|||
failed = aurora.Red("[✘]").String()
|
||||
|
||||
protocolTests = map[string]map[string]testutils.TestCase{
|
||||
"http": httpTestcases,
|
||||
"network": networkTestcases,
|
||||
"dns": dnsTestCases,
|
||||
"workflow": workflowTestcases,
|
||||
"loader": loaderTestcases,
|
||||
"websocket": websocketTestCases,
|
||||
"headless": headlessTestcases,
|
||||
"whois": whoisTestCases,
|
||||
"ssl": sslTestcases,
|
||||
"code": codeTestcases,
|
||||
"templatesPath": templatesPathTestCases,
|
||||
"templatesDir": templatesDirTestCases,
|
||||
"file": fileTestcases,
|
||||
"offlineHttp": offlineHttpTestcases,
|
||||
"http": httpTestcases,
|
||||
"network": networkTestcases,
|
||||
"dns": dnsTestCases,
|
||||
"workflow": workflowTestcases,
|
||||
"loader": loaderTestcases,
|
||||
"websocket": websocketTestCases,
|
||||
"headless": headlessTestcases,
|
||||
"whois": whoisTestCases,
|
||||
"ssl": sslTestcases,
|
||||
"code": codeTestcases,
|
||||
"templatesPath": templatesPathTestCases,
|
||||
"templatesDir": templatesDirTestCases,
|
||||
"file": fileTestcases,
|
||||
"offlineHttp": offlineHttpTestcases,
|
||||
"customConfigDir": customConfigDirTestCases,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
@ -32,7 +34,6 @@ func main() {
|
|||
if err := runner.ConfigureOptions(); err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
|
||||
}
|
||||
|
||||
readConfig()
|
||||
|
||||
// Profiling related code
|
||||
|
@ -181,6 +182,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
|||
flagSet.BoolVarP(&options.ShowMatchLine, "show-match-line", "sml", false, "show match lines for file templates, works with extractors only"),
|
||||
flagSet.BoolVar(&options.ZTLS, "ztls", false, "use ztls library with autofallback to standard one for tls13"),
|
||||
flagSet.StringVar(&options.SNI, "sni", "", "tls sni hostname to use (default: input domain name)"),
|
||||
flagSet.StringVar(&options.CustomConfigDir, "config-directory", "", "Override the default config path ($home/.config)"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("interactsh", "interactsh",
|
||||
|
@ -261,7 +263,29 @@ on extensive configurability, massive extensibility and ease of use.`)
|
|||
if options.LeaveDefaultPorts {
|
||||
http.LeaveDefaultPorts = true
|
||||
}
|
||||
|
||||
if options.CustomConfigDir != "" {
|
||||
originalIgnorePath := config.GetIgnoreFilePath()
|
||||
config.SetCustomConfigDirectory(options.CustomConfigDir)
|
||||
configPath := filepath.Join(options.CustomConfigDir, "config.yaml")
|
||||
ignoreFile := filepath.Join(options.CustomConfigDir, ".nuclei-ignore")
|
||||
if !fileutil.FileExists(ignoreFile) {
|
||||
_ = fileutil.CopyFile(originalIgnorePath, ignoreFile)
|
||||
}
|
||||
readConfigFile := func() error {
|
||||
if err := flagSet.MergeConfigFile(configPath); err != nil && !errors.Is(err, io.EOF) {
|
||||
defaultConfigPath, _ := goflags.GetConfigFilePath()
|
||||
err = fileutil.CopyFile(defaultConfigPath, configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New("reload the config file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := readConfigFile(); err != nil {
|
||||
_ = readConfigFile()
|
||||
}
|
||||
}
|
||||
if cfgFile != "" {
|
||||
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
|
||||
gologger.Fatal().Msgf("Could not read config: %s\n", err)
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/projectdiscovery/fileutil"
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
|
@ -18,7 +17,6 @@ import (
|
|||
func DoHealthCheck(options *types.Options) string {
|
||||
// RW permissions on config file
|
||||
cfgFilePath, _ := goflags.GetConfigFilePath()
|
||||
cfgFileFolder := filepath.Dir(cfgFilePath)
|
||||
var test strings.Builder
|
||||
test.WriteString(fmt.Sprintf("Version: %s\n", config.Version))
|
||||
test.WriteString(fmt.Sprintf("Operative System: %s\n", runtime.GOOS))
|
||||
|
@ -28,9 +26,13 @@ func DoHealthCheck(options *types.Options) string {
|
|||
|
||||
var testResult string
|
||||
|
||||
nucleiIgnorePath := filepath.Join(cfgFileFolder, ".nuclei-ignore")
|
||||
homedir, _ := homedir.Dir()
|
||||
nucleiTemplatePath := filepath.Join(homedir, "nuclei-templates/.checksum")
|
||||
nucleiIgnorePath := config.GetIgnoreFilePath()
|
||||
cf, _ := config.ReadConfiguration()
|
||||
templatePath := ""
|
||||
if cf != nil {
|
||||
templatePath = cf.TemplatesDirectory
|
||||
}
|
||||
nucleiTemplatePath := filepath.Join(templatePath, "/", ".checksum")
|
||||
for _, filename := range []string{cfgFilePath, nucleiIgnorePath, nucleiTemplatePath} {
|
||||
ok, err := fileutil.IsReadable(filename)
|
||||
if ok {
|
||||
|
|
|
@ -30,6 +30,14 @@ const nucleiConfigFilename = ".templates-config.json"
|
|||
// Version is the current version of nuclei
|
||||
const Version = `2.7.6`
|
||||
|
||||
var customConfigDirectory string
|
||||
|
||||
func SetCustomConfigDirectory(dir string) {
|
||||
customConfigDirectory = dir
|
||||
if !fileutil.FolderExists(dir) {
|
||||
_ = fileutil.CreateFolder(dir)
|
||||
}
|
||||
}
|
||||
func getConfigDetails() (string, error) {
|
||||
configDir, err := GetConfigDir()
|
||||
if err != nil {
|
||||
|
@ -42,7 +50,15 @@ func getConfigDetails() (string, error) {
|
|||
|
||||
// GetConfigDir returns the nuclei configuration directory
|
||||
func GetConfigDir() (string, error) {
|
||||
home, err := homedir.Dir()
|
||||
var (
|
||||
home string
|
||||
err error
|
||||
)
|
||||
if customConfigDirectory != "" {
|
||||
home = customConfigDirectory
|
||||
return home, nil
|
||||
}
|
||||
home, err = homedir.Dir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -55,7 +71,6 @@ func ReadConfiguration() (*Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := os.Open(templatesConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -100,7 +115,7 @@ type IgnoreFile struct {
|
|||
|
||||
// ReadIgnoreFile reads the nuclei ignore file returning blocked tags and paths
|
||||
func ReadIgnoreFile() IgnoreFile {
|
||||
file, err := os.Open(getIgnoreFilePath())
|
||||
file, err := os.Open(GetIgnoreFilePath())
|
||||
if err != nil {
|
||||
gologger.Error().Msgf("Could not read nuclei-ignore file: %s\n", err)
|
||||
return IgnoreFile{}
|
||||
|
@ -138,8 +153,8 @@ func OverrideIgnoreFilePath(customPath string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// getIgnoreFilePath returns the ignore file path for the runner
|
||||
func getIgnoreFilePath() string {
|
||||
// GetIgnoreFilePath returns the ignore file path for the runner
|
||||
func GetIgnoreFilePath() string {
|
||||
var defIgnoreFilePath string
|
||||
|
||||
if customIgnoreFilePath != "" {
|
||||
|
|
|
@ -236,6 +236,8 @@ type Options struct {
|
|||
InputReadTimeout time.Duration
|
||||
// Disable stdin for input processing
|
||||
DisableStdin bool
|
||||
// Custom Config Directory
|
||||
CustomConfigDir string
|
||||
}
|
||||
|
||||
func (options *Options) AddVarPayload(key string, value interface{}) {
|
||||
|
|
Loading…
Reference in New Issue