From 04c449a2975ebc44304b206bd188cff36c7d349c Mon Sep 17 00:00:00 2001 From: M09Ic Date: Mon, 12 Feb 2024 16:49:44 +0800 Subject: [PATCH] support config.yaml --- cmd/cmd.go | 39 +++++++---- config.yaml | 94 ++++++++++++++++++++++++++ go.mod | 19 ++++-- go.sum | 48 +++++++++---- internal/config.go | 146 ++++++++++++++++++++++++++++++++++++++++ internal/option.go | 163 +++++++++++++++++++++++---------------------- spray.go | 14 +++- 7 files changed, 411 insertions(+), 112 deletions(-) create mode 100644 config.yaml create mode 100644 internal/config.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 6f8d07a..7c1440e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -51,6 +51,30 @@ func Spray() { } return } + + // logs + logs.AddLevel(pkg.LogVerbose, "verbose", "[=] %s {{suffix}}") + if option.Debug { + logs.Log.SetLevel(logs.Debug) + } else if len(option.Verbose) > 0 { + logs.Log.SetLevel(pkg.LogVerbose) + } + + logs.Log.SetColorMap(map[logs.Level]func(string) string{ + logs.Info: logs.PurpleBold, + logs.Important: logs.GreenBold, + pkg.LogVerbose: logs.Green, + }) + + // check $home/.config/spray/config.yaml exist, if not, create it + if option.Config != "" { + err := internal.LoadConfig(option.Config, &option) + if err != nil { + logs.Log.Error(err.Error()) + return + } + } + if option.Version { fmt.Println(ver) return @@ -58,7 +82,7 @@ func Spray() { if option.Format != "" { internal.Format(option.Format, !option.NoColor) - os.Exit(0) + return } err = pkg.LoadTemplates() @@ -80,19 +104,6 @@ func Spray() { } } } - // logs - logs.AddLevel(pkg.LogVerbose, "verbose", "[=] %s {{suffix}}") - if option.Debug { - logs.Log.SetLevel(logs.Debug) - } else if len(option.Verbose) > 0 { - logs.Log.SetLevel(pkg.LogVerbose) - } - - logs.Log.SetColorMap(map[logs.Level]func(string) string{ - logs.Info: logs.PurpleBold, - logs.Important: logs.GreenBold, - pkg.LogVerbose: logs.Green, - }) // 初始化全局变量 pkg.Distance = uint8(option.SimhashDistance) diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..3280a11 --- /dev/null +++ b/config.yaml @@ -0,0 +1,94 @@ +input: + append-files: [] # Files, when found valid path, use append file new word with current path + append-rules: [] # Files, when found valid path, use append rule generator new word with current path + dictionaries: [] # Files, Multi,dict files, e.g.: -d 1.txt -d 2.txt + filter-rule: "" # String, filter rule, e.g.: --rule-filter '>8 <4' + rules: [] # Files, rule files, e.g.: -r rule1.txt -r rule2.txt + word: "" # String, word generate dsl, e.g.: -w test{?ld#4} + +functions: + extension: "" # String, add extensions (separated by commas), e.g.: -e jsp,jspx + exclude-extension: "" # String, exclude extensions (separated by commas), e.g.: --exclude-extension jsp,jspx + force-extension: false # Bool, force add extensions + remove-extension: "" # String, remove extensions (separated by commas), e.g.: --remove-extension jsp,jspx + prefix: [] # Strings, add prefix, e.g.: --prefix aaa --prefix bbb + suffix: [] # Strings, add suffix, e.g.: --suffix aaa --suffix bbb + upper: false # Bool, upper wordlist, e.g.: --uppercase + lower: false # Bool, lower wordlist, e.g.: --lowercase + replace: null # Strings, replace string, e.g.: --replace aaa:bbb --replace ccc:ddd + skip: [ ] # String, skip word when generate. rule, e.g.: --skip aaa + +misc: + mod: path # String, path/host spray + client: auto # String, Client type + thread: 20 # Int, number of threads per pool + pool: 5 # Int, Pool size + timeout: 5 # Int, timeout with request (seconds) + deadline: 999999 # Int, deadline (seconds) + proxy: "" # String, proxy address, e.g.: --proxy socks5://127.0.0.1:1080 + quiet: false # Bool, Quiet + debug: false # Bool, output debug info + verbose: [] # Bool, log verbose level, default 0, level1: -v, level2 -vv + no-bar: false # Bool, No progress bar + no-color: false # Bool, no color + +mode: + # status + black-status: "400,410" # Strings (comma split), custom black status + fuzzy-status: "500,501,502,503" # Strings (comma split), custom fuzzy status + unique-status: "403,200,404" # Strings (comma split), custom unique status + white-status: "200" # Strings (comma split), custom white status + + # check + check-only: false # Bool, check only + check-period: 200 # Int, check period when request + error-period: 10 # Int, check period when error + error-threshold: 20 # Int, break when the error exceeds the threshold + + # recursive + recursive: current.IsDir() # String, custom recursive rule, e.g.: --recursive current.IsDir() + depth: 0 # Int, recursive depth + + # crawl + scope: [] # String, custom scope, e.g.: --scope *.example.com + no-scope: false # Bool, no scope + + # other + index: / # String, custom index path + random: "" # String, custom random path + unique: false # Bool, unique response + distance: 5 # Int, simhash distance for unique response + force: false # Bool, skip error break + rate-limit: 0 # Int, request rate limit (rate/s), e.g.: --rate-limit 100 + retry: 0 # Int, retry count + +output: + output-file: "" # String, output filename + auto-file: false # Bool, auto generator output and fuzzy filename + dump: false # Bool, dump all request + dump-file: "" # String, dump all request, and write to filename + fuzzy: false # Bool, open fuzzy output + fuzzy-file: "" # String, fuzzy output filename + filter: "" # String, custom filter function, e.g.: --filter 'current.Body contains "hello"' + match: "" # String, custom match function, e.g.: --match 'current.Status != 200'' + format: "" # String, output format, e.g.: --format 1.json + output_probe: "" # String, output probes + +plugins: + all: false # Bool, enable all plugin + bak: false # Bool, enable bak found + common: false # Bool, enable common file found + crawl: false # Bool, enable crawl + crawl-depth: 3 # Int, crawl depth + extract: [] # Strings, extract response, e.g.: --extract js --extract ip --extract version:(.*?) + file-bak: false # Bool, enable valid result bak found, equal --append-rule rule/filebak.txt + finger: false # Bool, enable active finger detect + recon: false # Bool, enable recon + +request: + cookies: [] # Strings, custom cookie + headers: [] # Strings, custom headers, e.g.: --headers 'Auth: example_auth' + max-body-length: 100 # Int, max response body length (kb), default 100k, e.g. -max-length 1000 + useragent: "" # String, custom user-agent, e.g.: --user-agent Custom + random-useragent: false # Bool, use random with default user-agent + read-all: false # Bool, read all response body diff --git a/go.mod b/go.mod index ba0133d..2df1ade 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/chainreactors/spray -go 1.17 +go 1.19 require github.com/chainreactors/go-metrics v0.0.0-20220926021830-24787b7a10f8 @@ -12,25 +12,36 @@ require ( github.com/chainreactors/parsers v0.0.0-20240208143911-65866d5bbc6d github.com/chainreactors/utils v0.0.0-20231031063336-9477f1b23886 github.com/chainreactors/words v0.4.1-0.20240208114042-a1c5053345b0 + github.com/gookit/config/v2 v2.2.5 github.com/gosuri/uiprogress v0.0.1 github.com/jessevdk/go-flags v1.5.0 github.com/panjf2000/ants/v2 v2.7.0 github.com/valyala/fasthttp v1.43.0 golang.org/x/net v0.6.0 golang.org/x/time v0.3.0 - sigs.k8s.io/yaml v1.4.0 ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/andybalholm/brotli v1.0.4 // indirect + github.com/fatih/color v1.14.1 // indirect github.com/go-dedup/megophone v0.0.0-20170830025436-f01be21026f5 // indirect github.com/go-dedup/simhash v0.0.0-20170904020510-9ecaca7b509c // indirect github.com/go-dedup/text v0.0.0-20170907015346-8bb1b95e3cb7 // indirect + github.com/goccy/go-yaml v1.11.2 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/goutil v0.6.15 // indirect github.com/gosuri/uilive v0.0.4 // indirect github.com/klauspost/compress v1.15.10 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/twmb/murmur3 v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - golang.org/x/sys v0.5.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect ) diff --git a/go.sum b/go.sum index 23d1567..3c3401d 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/M09ic/go-ntlmssp v0.0.0-20230312133735-dcccd454dfe0/go.mod h1:yMNEF6ulbFipt3CakMhcmcNVACshPRG4Ap4l00V+mMs= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -18,18 +20,10 @@ github.com/chainreactors/logs v0.0.0-20240207121836-c946f072f81f/go.mod h1:6Mv6W github.com/chainreactors/neutron v0.0.0-20231221064706-fd6aaac9c50b/go.mod h1:Q6xCl+KaPtCDIziAHegFxdHOvg6DgpA6hcUWRnQKDPk= github.com/chainreactors/parsers v0.0.0-20231218072716-fb441aff745f/go.mod h1:ZHEkgxKf9DXoley2LUjdJkiSw08MC3vcJTxfqwYt2LU= github.com/chainreactors/parsers v0.0.0-20231220104848-3a0b5a5bd8dc/go.mod h1:V2w16sBSSiBlmsDR4A0Q9PIk9+TP/6coTXv6olvTI6M= -github.com/chainreactors/parsers v0.0.0-20240208083828-d2abbaa66a9c h1:zDqlRywqNXd2mnODH590mUiHAdaqjW/WBMu/E2mWLkw= -github.com/chainreactors/parsers v0.0.0-20240208083828-d2abbaa66a9c/go.mod h1:IS0hrYnccfJKU0NA12zdZk4mM7k/Qt4qnzMnFGBFLZI= -github.com/chainreactors/parsers v0.0.0-20240208143013-46f4b66a900a h1:jCCWBCTw/5L5FK6WMDqhz5ltMSjN0t0Jnlx+Lekzql4= -github.com/chainreactors/parsers v0.0.0-20240208143013-46f4b66a900a/go.mod h1:IS0hrYnccfJKU0NA12zdZk4mM7k/Qt4qnzMnFGBFLZI= -github.com/chainreactors/parsers v0.0.0-20240208143703-cdc9c2b86079 h1:00Pw9Beh1zUl7YaX5sD5V/a9To0PfQItolAOARlbxFo= -github.com/chainreactors/parsers v0.0.0-20240208143703-cdc9c2b86079/go.mod h1:IS0hrYnccfJKU0NA12zdZk4mM7k/Qt4qnzMnFGBFLZI= github.com/chainreactors/parsers v0.0.0-20240208143911-65866d5bbc6d h1:NFZLic9KNL1KdyvZFatRufXV9FJ3AXmKgTFQQ6Sz+Vk= github.com/chainreactors/parsers v0.0.0-20240208143911-65866d5bbc6d/go.mod h1:IS0hrYnccfJKU0NA12zdZk4mM7k/Qt4qnzMnFGBFLZI= github.com/chainreactors/utils v0.0.0-20231031063336-9477f1b23886 h1:lS2T/uE9tg1MNDPrb44wawbNlD24zBlWoG0H+ZdwDAk= github.com/chainreactors/utils v0.0.0-20231031063336-9477f1b23886/go.mod h1:JA4eiQZm+7AsfjXBcIzIdVKBEhDCb16eNtWFCGTxlvs= -github.com/chainreactors/words v0.4.1-0.20240206181137-09f7a0bc8f50 h1:5aK4k6ztjvDENa4zuxYPzQH2UAy9VM+tvOhpRSCCXWQ= -github.com/chainreactors/words v0.4.1-0.20240206181137-09f7a0bc8f50/go.mod h1:DUDx7PdsMEm5PvVhzkFyppzpiUhQb8dOJaWjVc1SMVk= github.com/chainreactors/words v0.4.1-0.20240208114042-a1c5053345b0 h1:7aAfDhZDLs6uiWNzYa68L4uzBX7ZIj7IT8v+AlmmpHw= github.com/chainreactors/words v0.4.1-0.20240208114042-a1c5053345b0/go.mod h1:DUDx7PdsMEm5PvVhzkFyppzpiUhQb8dOJaWjVc1SMVk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -38,6 +32,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-dedup/megophone v0.0.0-20170830025436-f01be21026f5 h1:4U+x+EB1P66zwYgTjxWXSOT8vF+651Ksr1lojiCZnT8= github.com/go-dedup/megophone v0.0.0-20170830025436-f01be21026f5/go.mod h1:poR/Cp00iqtqu9ltFwl6C00sKC0HY13u/Gh05ZBmP54= @@ -45,9 +41,21 @@ github.com/go-dedup/simhash v0.0.0-20170904020510-9ecaca7b509c h1:mucYYQn+sMGNSx github.com/go-dedup/simhash v0.0.0-20170904020510-9ecaca7b509c/go.mod h1:gO3u2bjRAgUaLdQd2XK+3oooxrheOAx1BzS7WmPzw1s= github.com/go-dedup/text v0.0.0-20170907015346-8bb1b95e3cb7 h1:11wFcswN+37U+ByjxdKzsRY5KzNqqq5Uk5ztxnLOc7w= github.com/go-dedup/text v0.0.0-20170907015346-8bb1b95e3cb7/go.mod h1:wSsK4VOECOSfSYTzkBFw+iGY7wj59e7X96ABtNj9aCQ= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= +github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/config/v2 v2.2.5 h1:RECbYYbtherywmzn3LNeu9NA5ZqhD7MSKEMsJ7l+MpU= +github.com/gookit/config/v2 v2.2.5/go.mod h1:NeX+yiNYn6Ei10eJvCQFXuHEPIE/IPS8bqaFIsszzaM= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E= github.com/gosuri/uilive v0.0.4 h1:hUEBpQDj8D8jXgtCdBu7sWsy5sbW/5GhuO8KBwJ2jyY= github.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI= github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJSxw= @@ -62,9 +70,15 @@ github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE= github.com/panjf2000/ants/v2 v2.7.0 h1:Y3Bgpfo9HDkBoHNVFbMfY5mAvi5TAA17y3HbzQ74p5Y= @@ -79,8 +93,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= @@ -91,11 +105,15 @@ github.com/valyala/fasthttp v1.43.0 h1:Gy4sb32C98fbzVWZlTM1oTMdLWGyvxR03VhM6cBIU github.com/valyala/fasthttp v1.43.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -109,8 +127,9 @@ golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -122,11 +141,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -141,6 +163,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/config.go b/internal/config.go new file mode 100644 index 0000000..c79df68 --- /dev/null +++ b/internal/config.go @@ -0,0 +1,146 @@ +package internal + +import ( + "fmt" + "github.com/goccy/go-yaml" + "github.com/gookit/config/v2" + "reflect" + "strconv" +) + +//var ( +// defaultConfigPath = ".config/spray/" +// defaultConfigFile = "config.yaml" +//) +// +//func LoadDefault(v interface{}) { +// dir, err := os.UserHomeDir() +// if err != nil { +// logs.Log.Error(err.Error()) +// return +// } +// if !files.IsExist(filepath.Join(dir, defaultConfigPath, defaultConfigFile)) { +// err := os.MkdirAll(filepath.Join(dir, defaultConfigPath), 0o700) +// if err != nil { +// logs.Log.Error(err.Error()) +// return +// } +// f, err := os.Create(filepath.Join(dir, defaultConfigPath, defaultConfigFile)) +// if err != nil { +// logs.Log.Error(err.Error()) +// return +// } +// err = LoadConfig(filepath.Join(dir, defaultConfigPath, defaultConfigFile), v) +// if err != nil { +// logs.Log.Error(err.Error()) +// return +// } +// var buf bytes.Buffer +// _, err = config.DumpTo(&buf, config.Yaml) +// if err != nil { +// logs.Log.Error(err.Error()) +// return +// } +// fmt.Println(buf.String()) +// f.Sync() +// } +//} + +func LoadConfig(filename string, v interface{}) error { + err := config.LoadFiles(filename) + if err != nil { + return err + } + err = config.Decode(v) + if err != nil { + return err + } + return nil +} + +func convertToFieldType(fieldType reflect.StructField, defaultVal string) interface{} { + switch fieldType.Type.Kind() { + case reflect.Bool: + val, err := strconv.ParseBool(defaultVal) + if err == nil { + return val + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + val, err := strconv.ParseInt(defaultVal, 10, 64) + if err == nil { + return val + } + case reflect.Float32, reflect.Float64: + val, err := strconv.ParseFloat(defaultVal, 64) + if err == nil { + return val + } + case reflect.String: + return defaultVal + // 可以根据需要扩展其他类型 + } + return nil // 如果转换失败或类型不受支持,返回nil +} + +func setFieldValue(field reflect.Value) interface{} { + switch field.Kind() { + case reflect.Bool: + return false + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return 0 + case reflect.Float32, reflect.Float64: + return 0.0 + case reflect.Slice, reflect.Array: + return []interface{}{} // 返回一个空切片 + case reflect.String: + return "" + case reflect.Struct: + return make(map[string]interface{}) + default: + return nil + } +} + +// extractConfigAndDefaults 提取带有 `config` 和 `default` 标签的字段 +func extractConfigAndDefaults(v reflect.Value, result map[string]interface{}) { + t := v.Type() + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + fieldType := t.Field(i) + configTag := fieldType.Tag.Get("config") + defaultTag := fieldType.Tag.Get("default") + + if configTag != "" { + var value interface{} + if defaultTag != "" { + value = convertToFieldType(fieldType, defaultTag) + } else { + value = setFieldValue(field) + } + if field.Kind() == reflect.Struct { + nestedResult := make(map[string]interface{}) + extractConfigAndDefaults(field, nestedResult) + result[configTag] = nestedResult + } else { + result[configTag] = value + } + } + } +} + +func initDefaultConfig(cfg interface{}) (string, error) { + v := reflect.ValueOf(cfg) + if v.Kind() != reflect.Struct { + return "", fmt.Errorf("expected a struct, got %s", v.Kind()) + } + + result := make(map[string]interface{}) + extractConfigAndDefaults(v, result) + + yamlData, err := yaml.Marshal(result) + if err != nil { + return "", err + } + + return string(yamlData), nil +} diff --git a/internal/option.go b/internal/option.go index 54c8f6b..8822f4b 100644 --- a/internal/option.go +++ b/internal/option.go @@ -28,116 +28,117 @@ var ( ) type Option struct { - InputOptions `group:"Input Options"` - FunctionOptions `group:"Function Options"` - OutputOptions `group:"Output Options"` - PluginOptions `group:"Plugin Options"` - RequestOptions `group:"Request Options"` - ModeOptions `group:"Modify Options"` - MiscOptions `group:"Miscellaneous Options"` + InputOptions `group:"Input Options" config:"input" default:""` + FunctionOptions `group:"Function Options" config:"functions" default:""` + OutputOptions `group:"Output Options" config:"output"` + PluginOptions `group:"Plugin Options" config:"plugins"` + RequestOptions `group:"Request Options" config:"request"` + ModeOptions `group:"Modify Options" config:"mode"` + MiscOptions `group:"Miscellaneous Options" config:"misc"` } type InputOptions struct { - ResumeFrom string `long:"resume"` + ResumeFrom string `long:"resume" description:"File, resume filename" ` + Config string `short:"c" long:"config" description:"File, config filename"` URL []string `short:"u" long:"url" description:"Strings, input baseurl, e.g.: http://google.com"` URLFile string `short:"l" long:"list" description:"File, input filename"` PortRange string `short:"p" long:"port" description:"String, input port range, e.g.: 80,8080-8090,db"` - CIDRs string `short:"c" long:"cidr" description:"String, input cidr, e.g.: 1.1.1.1/24 "` + CIDRs string `long:"cidr" description:"String, input cidr, e.g.: 1.1.1.1/24 "` //Raw string `long:"raw" description:"File, input raw request filename"` - Dictionaries []string `short:"d" long:"dict" description:"Files, Multi,dict files, e.g.: -d 1.txt -d 2.txt"` + Dictionaries []string `short:"d" long:"dict" description:"Files, Multi,dict files, e.g.: -d 1.txt -d 2.txt" config:"dictionaries"` Offset int `long:"offset" description:"Int, wordlist offset"` Limit int `long:"limit" description:"Int, wordlist limit, start with offset. e.g.: --offset 1000 --limit 100"` - Word string `short:"w" long:"word" description:"String, word generate dsl, e.g.: -w test{?ld#4}"` - Rules []string `short:"r" long:"rules" description:"Files, rule files, e.g.: -r rule1.txt -r rule2.txt"` - AppendRule []string `long:"append-rule" description:"Files, when found valid path , use append rule generator new word with current path"` - FilterRule string `long:"filter-rule" description:"String, filter rule, e.g.: --rule-filter '>8 <4'"` - AppendFile []string `long:"append-file" description:"Files, when found valid path , use append file new word with current path"` + Word string `short:"w" long:"word" description:"String, word generate dsl, e.g.: -w test{?ld#4}" config:"word"` + Rules []string `short:"r" long:"rules" description:"Files, rule files, e.g.: -r rule1.txt -r rule2.txt" config:"rules"` + AppendRule []string `long:"append-rule" description:"Files, when found valid path , use append rule generator new word with current path" config:"append-rules"` + FilterRule string `long:"filter-rule" description:"String, filter rule, e.g.: --rule-filter '>8 <4'" config:"filter-rule"` + AppendFile []string `long:"append-file" description:"Files, when found valid path , use append file new word with current path" config:"append-files"` } type FunctionOptions struct { - Extensions string `short:"e" long:"extension" description:"String, add extensions (separated by commas), e.g.: -e jsp,jspx"` - ForceExtension bool `long:"force-extension" description:"Bool, force add extensions"` - ExcludeExtensions string `long:"exclude-extension" description:"String, exclude extensions (separated by commas), e.g.: --exclude-extension jsp,jspx"` - RemoveExtensions string `long:"remove-extension" description:"String, remove extensions (separated by commas), e.g.: --remove-extension jsp,jspx"` - Uppercase bool `short:"U" long:"uppercase" description:"Bool, upper wordlist, e.g.: --uppercase"` - Lowercase bool `short:"L" long:"lowercase" description:"Bool, lower wordlist, e.g.: --lowercase"` - Prefixes []string `long:"prefix" description:"Strings, add prefix, e.g.: --prefix aaa --prefix bbb"` - Suffixes []string `long:"suffix" description:"Strings, add suffix, e.g.: --suffix aaa --suffix bbb"` - Replaces map[string]string `long:"replace" description:"Strings, replace string, e.g.: --replace aaa:bbb --replace ccc:ddd"` - Skips []string `long:"skip" description:"String, skip word when generate. rule, e.g.: --skip aaa"` + Extensions string `short:"e" long:"extension" description:"String, add extensions (separated by commas), e.g.: -e jsp,jspx" config:"extension"` + ForceExtension bool `long:"force-extension" description:"Bool, force add extensions" config:"force-extension"` + ExcludeExtensions string `long:"exclude-extension" description:"String, exclude extensions (separated by commas), e.g.: --exclude-extension jsp,jspx" config:"exclude-extension"` + RemoveExtensions string `long:"remove-extension" description:"String, remove extensions (separated by commas), e.g.: --remove-extension jsp,jspx" config:"remove-extension"` + Uppercase bool `short:"U" long:"uppercase" description:"Bool, upper wordlist, e.g.: --uppercase" config:"upper"` + Lowercase bool `short:"L" long:"lowercase" description:"Bool, lower wordlist, e.g.: --lowercase" config:"lower"` + Prefixes []string `long:"prefix" description:"Strings, add prefix, e.g.: --prefix aaa --prefix bbb" config:"prefix"` + Suffixes []string `long:"suffix" description:"Strings, add suffix, e.g.: --suffix aaa --suffix bbb" config:"suffix"` + Replaces map[string]string `long:"replace" description:"Strings, replace string, e.g.: --replace aaa:bbb --replace ccc:ddd" config:"replace"` + Skips []string `long:"skip" description:"String, skip word when generate. rule, e.g.: --skip aaa" config:"skip"` //SkipEval string `long:"skip-eval" description:"String, skip word when generate. rule, e.g.: --skip-eval 'current.Length < 4'"` } type OutputOptions struct { - Match string `long:"match" description:"String, custom match function, e.g.: --match 'current.Status != 200''" json:"match,omitempty"` - Filter string `long:"filter" description:"String, custom filter function, e.g.: --filter 'current.Body contains \"hello\"'" json:"filter,omitempty"` - OutputFile string `short:"f" long:"file" description:"String, output filename" json:"output_file,omitempty"` - Format string `short:"F" long:"format" description:"String, output format, e.g.: --format 1.json"` - FuzzyFile string `long:"fuzzy-file" description:"String, fuzzy output filename" json:"fuzzy_file,omitempty"` - DumpFile string `long:"dump-file" description:"String, dump all request, and write to filename"` - Dump bool `long:"dump" description:"Bool, dump all request"` - AutoFile bool `long:"auto-file" description:"Bool, auto generator output and fuzzy filename" ` - Fuzzy bool `long:"fuzzy" description:"String, open fuzzy output" json:"fuzzy,omitempty"` - OutputProbe string `short:"o" long:"probe" description:"String, output format" json:"output_probe,omitempty"` + Match string `long:"match" description:"String, custom match function, e.g.: --match 'current.Status != 200''" config:"match" ` + Filter string `long:"filter" description:"String, custom filter function, e.g.: --filter 'current.Body contains \"hello\"'" config:"filter"` + Fuzzy bool `long:"fuzzy" description:"String, open fuzzy output" config:"fuzzy"` + OutputFile string `short:"f" long:"file" description:"String, output filename" json:"output_file,omitempty" config:"output-file"` + FuzzyFile string `long:"fuzzy-file" description:"String, fuzzy output filename" json:"fuzzy_file,omitempty" config:"fuzzy-file"` + DumpFile string `long:"dump-file" description:"String, dump all request, and write to filename" config:"dump-file"` + Dump bool `long:"dump" description:"Bool, dump all request" config:"dump"` + AutoFile bool `long:"auto-file" description:"Bool, auto generator output and fuzzy filename" config:"auto-file"` + Format string `short:"F" long:"format" description:"String, output format, e.g.: --format 1.json" config:"format"` + OutputProbe string `short:"o" long:"probe" description:"String, output format" config:"output_probe"` } type RequestOptions struct { - Headers []string `long:"header" description:"Strings, custom headers, e.g.: --headers 'Auth: example_auth'"` - UserAgent string `long:"user-agent" description:"String, custom user-agent, e.g.: --user-agent Custom"` - RandomUserAgent bool `long:"random-agent" description:"Bool, use random with default user-agent"` - Cookie []string `long:"cookie" description:"Strings, custom cookie"` - ReadAll bool `long:"read-all" description:"Bool, read all response body"` - MaxBodyLength int `long:"max-length" default:"100" description:"Int, max response body length (kb), default 100k, e.g. -max-length 1000"` - Proxy string `long:"proxy" default:"" description:"String, proxy address, e.g.: --proxy socks5://127.0.0.1:1080"` + Headers []string `long:"header" description:"Strings, custom headers, e.g.: --headers 'Auth: example_auth'" config:"headers"` + UserAgent string `long:"user-agent" description:"String, custom user-agent, e.g.: --user-agent Custom" config:"useragent"` + RandomUserAgent bool `long:"random-agent" description:"Bool, use random with default user-agent" config:"random-useragent"` + Cookie []string `long:"cookie" description:"Strings, custom cookie" config:"cookies"` + ReadAll bool `long:"read-all" description:"Bool, read all response body" config:"read-all"` + MaxBodyLength int `long:"max-length" default:"100" description:"Int, max response body length (kb), default 100k, e.g. -max-length 1000" config:"max-body-length"` } type PluginOptions struct { - Advance bool `short:"a" long:"advance" description:"Bool, enable crawl and active"` - Extracts []string `long:"extract" description:"Strings, extract response, e.g.: --extract js --extract ip --extract version:(.*?)"` - Recon bool `long:"recon" description:"Bool, enable recon"` - Finger bool `long:"finger" description:"Bool, enable active finger detect"` - Bak bool `long:"bak" description:"Bool, enable bak found"` - FileBak bool `long:"file-bak" description:"Bool, enable valid result bak found, equal --append-rule rule/filebak.txt"` - Common bool `long:"common" description:"Bool, enable common file found"` - Crawl bool `long:"crawl" description:"Bool, enable crawl"` - CrawlDepth int `long:"crawl-depth" default:"3" description:"Int, crawl depth"` + Advance bool `short:"a" long:"advance" description:"Bool, enable all plugin" config:"all" ` + Extracts []string `long:"extract" description:"Strings, extract response, e.g.: --extract js --extract ip --extract version:(.*?)" config:"extract"` + Recon bool `long:"recon" description:"Bool, enable recon" config:"recon"` + Finger bool `long:"finger" description:"Bool, enable active finger detect" config:"finger"` + Bak bool `long:"bak" description:"Bool, enable bak found" config:"bak"` + FileBak bool `long:"file-bak" description:"Bool, enable valid result bak found, equal --append-rule rule/filebak.txt" config:"file-bak"` + Common bool `long:"common" description:"Bool, enable common file found" config:"common"` + Crawl bool `long:"crawl" description:"Bool, enable crawl" config:"crawl"` + CrawlDepth int `long:"crawl-depth" default:"3" description:"Int, crawl depth" config:"crawl-depth"` } type ModeOptions struct { - RateLimit int `long:"rate-limit" default:"0" description:"Int, request rate limit (rate/s), e.g.: --rate-limit 100"` - Force bool `long:"force" description:"Bool, skip error break"` - CheckOnly bool `long:"check-only" description:"Bool, check only"` - NoScope bool `long:"no-scope" description:"Bool, no scope"` - Scope []string `long:"scope" description:"String, custom scope, e.g.: --scope *.example.com"` - Recursive string `long:"recursive" default:"current.IsDir()" description:"String,custom recursive rule, e.g.: --recursive current.IsDir()"` - Depth int `long:"depth" default:"0" description:"Int, recursive depth"` - Index string `long:"index" default:"/" description:"String, custom index path"` - Random string `long:"random" default:"" description:"String, custom random path"` - CheckPeriod int `long:"check-period" default:"200" description:"Int, check period when request"` - ErrPeriod int `long:"error-period" default:"10" description:"Int, check period when error"` - BreakThreshold int `long:"error-threshold" default:"20" description:"Int, break when the error exceeds the threshold "` - BlackStatus string `long:"black-status" default:"400,410" description:"Strings (comma split),custom black status, "` - WhiteStatus string `long:"white-status" default:"200" description:"Strings (comma split), custom white status"` - FuzzyStatus string `long:"fuzzy-status" default:"500,501,502,503" description:"Strings (comma split), custom fuzzy status"` - UniqueStatus string `long:"unique-status" default:"403,200,404" description:"Strings (comma split), custom unique status"` - Unique bool `long:"unique" description:"Bool, unique response"` - RetryCount int `long:"retry" default:"0" description:"Int, retry count"` - SimhashDistance int `long:"distance" default:"5"` + RateLimit int `long:"rate-limit" default:"0" description:"Int, request rate limit (rate/s), e.g.: --rate-limit 100" config:"rate-limit"` + Force bool `long:"force" description:"Bool, skip error break" config:"force"` + CheckOnly bool `long:"check-only" description:"Bool, check only" config:"check-only"` + NoScope bool `long:"no-scope" description:"Bool, no scope" config:"no-scope"` + Scope []string `long:"scope" description:"String, custom scope, e.g.: --scope *.example.com" config:"scope"` + Recursive string `long:"recursive" default:"current.IsDir()" description:"String,custom recursive rule, e.g.: --recursive current.IsDir()" config:"recursive"` + Depth int `long:"depth" default:"0" description:"Int, recursive depth" config:"depth"` + Index string `long:"index" default:"/" description:"String, custom index path" config:"index"` + Random string `long:"random" default:"" description:"String, custom random path" config:"random"` + CheckPeriod int `long:"check-period" default:"200" description:"Int, check period when request" config:"check-period"` + ErrPeriod int `long:"error-period" default:"10" description:"Int, check period when error" config:"error-period"` + BreakThreshold int `long:"error-threshold" default:"20" description:"Int, break when the error exceeds the threshold" config:"error-threshold"` + BlackStatus string `long:"black-status" default:"400,410" description:"Strings (comma split),custom black status" config:"black-status"` + WhiteStatus string `long:"white-status" default:"200" description:"Strings (comma split), custom white status" config:"white-status"` + FuzzyStatus string `long:"fuzzy-status" default:"500,501,502,503" description:"Strings (comma split), custom fuzzy status" config:"fuzzy-status"` + UniqueStatus string `long:"unique-status" default:"403,200,404" description:"Strings (comma split), custom unique status" config:"unique-status"` + Unique bool `long:"unique" description:"Bool, unique response" config:"unique"` + RetryCount int `long:"retry" default:"0" description:"Int, retry count" config:"retry"` + SimhashDistance int `long:"distance" default:"5" config:"distance"` } type MiscOptions struct { - Mod string `short:"m" long:"mod" default:"path" choice:"path" choice:"host" description:"String, path/host spray"` - Client string `short:"C" long:"client" default:"auto" choice:"fast" choice:"standard" choice:"auto" description:"String, Client type"` - Deadline int `long:"deadline" default:"999999" description:"Int, deadline (seconds)"` // todo 总的超时时间,适配云函数的deadline - Timeout int `long:"timeout" default:"5" description:"Int, timeout with request (seconds)"` - PoolSize int `short:"P" long:"pool" default:"5" description:"Int, Pool size"` - Threads int `short:"t" long:"thread" default:"20" description:"Int, number of threads per pool"` - Debug bool `long:"debug" description:"Bool, output debug info"` + Mod string `short:"m" long:"mod" default:"path" choice:"path" choice:"host" description:"String, path/host spray" config:"mod"` + Client string `short:"C" long:"client" default:"auto" choice:"fast" choice:"standard" choice:"auto" description:"String, Client type" config:"client"` + Deadline int `long:"deadline" default:"999999" description:"Int, deadline (seconds)" config:"deadline"` // todo 总的超时时间,适配云函数的deadline + Timeout int `long:"timeout" default:"5" description:"Int, timeout with request (seconds)" config:"timeout"` + PoolSize int `short:"P" long:"pool" default:"5" description:"Int, Pool size" config:"pool"` + Threads int `short:"t" long:"thread" default:"20" description:"Int, number of threads per pool" config:"thread"` + Debug bool `long:"debug" description:"Bool, output debug info" config:"debug"` Version bool `long:"version" description:"Bool, show version"` - Verbose []bool `short:"v" description:"Bool, log verbose level ,default 0, level1: -v level2 -vv "` - Quiet bool `short:"q" long:"quiet" description:"Bool, Quiet"` - NoColor bool `long:"no-color" description:"Bool, no color"` - NoBar bool `long:"no-bar" description:"Bool, No progress bar"` + Verbose []bool `short:"v" description:"Bool, log verbose level ,default 0, level1: -v level2 -vv " config:"verbose"` + Quiet bool `short:"q" long:"quiet" description:"Bool, Quiet" config:"quiet"` + NoColor bool `long:"no-color" description:"Bool, no color" config:"no-color"` + NoBar bool `long:"no-bar" description:"Bool, No progress bar" config:"no-bar"` + Proxy string `long:"proxy" default:"" description:"String, proxy address, e.g.: --proxy socks5://127.0.0.1:1080" config:"proxy"` } func (opt *Option) PrepareRunner() (*Runner, error) { diff --git a/spray.go b/spray.go index b93658a..71b68c7 100644 --- a/spray.go +++ b/spray.go @@ -1,7 +1,19 @@ //go:generate go run templates/templates_gen.go -t templates -o pkg/templates.go -need spray package main -import "github.com/chainreactors/spray/cmd" +import ( + "github.com/chainreactors/spray/cmd" + "github.com/gookit/config/v2" + "github.com/gookit/config/v2/yaml" +) + +func init() { + config.WithOptions(func(opt *config.Options) { + opt.DecoderConfig.TagName = "config" + opt.ParseDefault = true + }) + config.AddDriver(yaml.Driver) +} func main() { //f, _ := os.Create("cpu.txt")