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 fix
dev
Sami 2022-08-25 05:40:07 -05:00 committed by GitHub
parent 606c361b2a
commit 0aac36a44b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 26 deletions

View File

@ -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)
}

View File

@ -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,
}
)

View File

@ -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)

View File

@ -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 {

View File

@ -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 != "" {

View File

@ -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{}) {