给全局的输出添加配色, 可以使用--no-color或-q关闭

This commit is contained in:
M09Ic 2022-12-15 00:19:06 +08:00
parent 34e544deaf
commit 073cf2a095
8 changed files with 136 additions and 17 deletions

View File

@ -284,7 +284,7 @@ spray支持断点续传, 可以通过`--resume-from`参数指定断点文件.
断点续传支持比命令行更自由的字典配置. 每个任务都可以拥有独立的-w/-r/-d配置. 因此某些特殊情况下要进行批量操作, 可以通过脚本去构造对应的stat文件, 实现更加自由的任务配置.
### 递归
spray并不鼓励使用递归, 因为spray的定位是批量从反代/cdn中发现隐形资产. 不管是因为批量, 还是因为反代/cdn, 99.9的情况都用不到递归.
spray并不鼓励使用递归, 因为spray的定位是批量从反代/cdn中发现隐形资产. 不管是因为批量, 还是因为反代/cdn, 绝大多数的情况都用不到递归.
但为了兼容某些极为罕见的情况, spray依旧保留了递归的功能.

4
go.mod
View File

@ -7,9 +7,9 @@ require (
github.com/chainreactors/go-metrics v0.0.0-20220926021830-24787b7a10f8
github.com/chainreactors/gogo/v2 v2.10.1
github.com/chainreactors/ipcs v0.0.13
github.com/chainreactors/logs v0.6.2
github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580
github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410
github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad
github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9
)
require (

10
go.sum
View File

@ -19,6 +19,14 @@ github.com/chainreactors/ipcs v0.0.13/go.mod h1:E9M3Ohyq0TYQLlV4i2dbM9ThBZB1Nnd7
github.com/chainreactors/logs v0.6.1/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/logs v0.6.2 h1:Yz5oayjwxO6KkjfjnmtT5WKbWjTaBdttFcneaFTpBe0=
github.com/chainreactors/logs v0.6.2/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/logs v0.7.1-0.20221214130332-9bc5319887fe h1:FRMBKyuuh6EoHefqprP+pSblHrUxTaSp9GPJahYa+Fc=
github.com/chainreactors/logs v0.7.1-0.20221214130332-9bc5319887fe/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/logs v0.7.1-0.20221214130646-2e08f98a1f71 h1:SpyPYjRihGyBiqoMUggXzCc4t9A0tmAvYdjghDG8s+M=
github.com/chainreactors/logs v0.7.1-0.20221214130646-2e08f98a1f71/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/logs v0.7.1-0.20221214152543-60422cf64610 h1:ErODIlY9NmlrwEi6np3bm7HmuRZSaH3+ID2fJ2ViUpM=
github.com/chainreactors/logs v0.7.1-0.20221214152543-60422cf64610/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580 h1:28gbL1t+Mm4AoP1MeKM9oeSHoPcUwIrzrLtmdusHMIo=
github.com/chainreactors/logs v0.7.1-0.20221214153111-85f123ff6580/go.mod h1:Y0EtAnoF0kiASIJUnXN0pcOt420iRpHOAnOhEphzRHA=
github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410 h1:K7EV0wtUuN6Rvh/MgqaBXyElD3guPsgNR5kF8nrV7iw=
github.com/chainreactors/parsers v0.2.9-0.20221210155102-cc0814762410/go.mod h1:Z9weht+lnFCk7UcwqFu6lXpS7u5vttiy0AJYOAyCCLA=
github.com/chainreactors/words v0.3.2-0.20221212161820-bae5f18558db h1:Rv6mcLAKXRXoZuifCwGTlXnuDbDpbDKC0JsTI1op/OA=
@ -27,6 +35,8 @@ github.com/chainreactors/words v0.3.2-0.20221214061028-a7cf9f9f8ddb h1:9AV8SH+Sv
github.com/chainreactors/words v0.3.2-0.20221214061028-a7cf9f9f8ddb/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w=
github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad h1:uL3TIQgvFY7dLoX0tAzIIXilCPIcNeLz/124gs+SA/Q=
github.com/chainreactors/words v0.3.2-0.20221214062855-48dff09b01ad/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w=
github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9 h1:IUNopSuorfINmn4pOuSwZtxJbg8zsRIZ67a33SiYoQ0=
github.com/chainreactors/words v0.3.2-0.20221214154622-381fc37abdf9/go.mod h1:QIWX1vMT5j/Mp9zx3/wgZh3FqskhjCbo/3Ffy/Hxj9w=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=

View File

@ -92,6 +92,7 @@ type MiscOptions struct {
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 (seconds)"`
Debug bool `long:"debug" description:"Bool, output debug info"`
NoColor bool `long:"no-color" description:"Bool, no color"`
Quiet bool `short:"q" long:"quiet" description:"Bool, Quiet"`
NoBar bool `long:"no-bar" description:"Bool, No progress bar"`
Mod string `short:"m" long:"mod" default:"path" choice:"path" choice:"host" description:"String, path/host spray"`
@ -139,11 +140,19 @@ func (opt *Option) PrepareRunner() (*Runner, error) {
}
}
// 一些全局变量初始化
if !opt.NoColor {
logs.Log.Color = true
logs.DefaultColorMap[logs.Info] = logs.PurpleBold
logs.DefaultColorMap[logs.Important] = logs.Green
r.Color = true
}
if opt.Debug {
logs.Log.Level = logs.Debug
}
if opt.Quiet {
logs.Log.Quiet = true
logs.Log.Color = false
r.Color = false
}
if !(opt.Quiet || opt.NoBar) {
r.Progress.Start()

View File

@ -230,7 +230,7 @@ func (pool *Pool) Init() error {
return fmt.Errorf(pool.index.String())
}
pool.index.Collect()
logs.Log.Important("[baseline.index] " + pool.index.String())
logs.Log.Info("[baseline.index] " + pool.index.String())
pool.initwg.Add(1)
pool.reqPool.Invoke(newUnit(pkg.RandPath(), InitRandomSource))
@ -240,14 +240,14 @@ func (pool *Pool) Init() error {
return fmt.Errorf(pool.random.String())
}
pool.random.Collect()
logs.Log.Important("[baseline.random] " + pool.random.String())
logs.Log.Info("[baseline.random] " + pool.random.String())
if pool.random.RedirectURL != "" {
// 自定协议升级
// 某些网站http会重定向到https, 如果发现随机目录出现这种情况, 则自定将baseurl升级为https
rurl, err := url.Parse(pool.random.RedirectURL)
if err == nil && rurl.Hostname() == pool.random.Url.Hostname() && pool.random.Url.Scheme == "http" && rurl.Scheme == "https" {
logs.Log.Importantf("baseurl %s upgrade http to https", pool.BaseURL)
logs.Log.Infof("baseurl %s upgrade http to https", pool.BaseURL)
pool.BaseURL = strings.Replace(pool.BaseURL, "http", "https", 1)
}
}
@ -435,7 +435,7 @@ func (pool *Pool) addFuzzyBaseline(bl *pkg.Baseline) {
pool.locker.Lock()
pool.baselines[bl.Status] = bl
pool.locker.Unlock()
logs.Log.Importantf("[baseline.%dinit] %s", bl.Status, bl.String())
logs.Log.Infof("[baseline.%dinit] %s", bl.Status, bl.String())
}
}

View File

@ -68,6 +68,7 @@ type Runner struct {
CheckPeriod int
ErrPeriod int
BreakThreshold int
Color bool
CheckOnly bool
Force bool
IgnoreWaf bool
@ -198,8 +199,14 @@ func (r *Runner) Prepare(ctx context.Context) error {
}
pool.Run(ctx, pool.Statistor.Offset, limit)
logs.Log.Important(pool.Statistor.String())
logs.Log.Important(pool.Statistor.Detail())
if r.Color {
logs.Log.Important(pool.Statistor.ColorString())
logs.Log.Important(pool.Statistor.ColorDetail())
} else {
logs.Log.Important(pool.Statistor.String())
logs.Log.Important(pool.Statistor.Detail())
}
if r.StatFile != nil {
r.StatFile.SafeWrite(pool.Statistor.Json())
r.StatFile.SafeSync()
@ -314,13 +321,26 @@ func (r *Runner) Outputting() {
} else {
if len(r.Probes) > 0 {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console("[+] " + bl.Format(r.Probes) + "\n")
if r.Color {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console(logs.GreenBold("[+] " + bl.Format(r.Probes) + "\n"))
}
} else {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console("[+] " + bl.Format(r.Probes) + "\n")
}
}
} else {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console("[+] " + bl.String() + "\n")
if r.Color {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console(logs.GreenBold("[+] " + bl.ColorString() + "\n"))
}
} else {
saveFunc = func(bl *pkg.Baseline) {
logs.Log.Console("[+] " + bl.String() + "\n")
}
}
}
}
@ -340,7 +360,12 @@ func (r *Runner) Outputting() {
r.AddPool(&Task{baseUrl: bl.UrlString, depth: bl.RecuDepth + 1})
}
} else {
logs.Log.Debug(bl.String())
if r.Color {
logs.Log.Debug(bl.ColorString())
} else {
logs.Log.Debug(bl.String())
}
}
}
}
@ -353,9 +378,13 @@ func (r *Runner) Outputting() {
r.FuzzyFile.SafeWrite(bl.Jsonify() + "\n")
}
} else {
fuzzySaveFunc = func(bl *pkg.Baseline) {
if r.Fuzzy {
logs.Log.Console("[baseline.fuzzy] " + bl.String() + "\n")
if r.Color {
fuzzySaveFunc = func(bl *pkg.Baseline) {
logs.Log.Console(logs.GreenBold("[fuzzy] " + bl.ColorString() + "\n"))
}
} else {
fuzzySaveFunc = func(bl *pkg.Baseline) {
logs.Log.Console("[fuzzy] " + bl.String() + "\n")
}
}
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"github.com/chainreactors/gogo/v2/pkg/utils"
"github.com/chainreactors/logs"
"github.com/chainreactors/parsers"
"github.com/chainreactors/spray/pkg/ihttp"
"net/url"
@ -227,6 +228,47 @@ func (bl *Baseline) Format(probes []string) string {
return line.String()
}
func (bl *Baseline) ColorString() string {
var line strings.Builder
if bl.FrontURL != "" {
line.WriteString("\t")
line.WriteString(logs.CyanLine(bl.FrontURL))
line.WriteString(" --> ")
}
line.WriteString(logs.GreenLine(bl.UrlString))
if bl.Host != "" {
line.WriteString(" (" + bl.Host + ")")
}
if bl.Reason != "" {
line.WriteString(" [reason: ")
line.WriteString(logs.YellowBold(bl.Reason))
line.WriteString("]")
}
if bl.ErrString != "" {
line.WriteString(" [err: ")
line.WriteString(logs.RedBold(bl.ErrString))
line.WriteString("]")
return line.String()
}
line.WriteString(" - ")
line.WriteString(logs.GreenBold(strconv.Itoa(bl.Status)))
line.WriteString(" - ")
line.WriteString(logs.Blue(strconv.Itoa(bl.BodyLength)))
line.WriteString(" - ")
line.WriteString(logs.Blue(strconv.Itoa(int(bl.Spended)) + "ms"))
line.WriteString(logs.GreenLine(bl.Additional("title")))
line.WriteString(logs.Blue(bl.Frameworks.String()))
line.WriteString(logs.Blue(bl.Extracteds.String()))
if bl.RedirectURL != "" {
line.WriteString(" --> ")
line.WriteString(logs.CyanLine(bl.RedirectURL))
line.WriteString(" ")
}
return line.String()
}
func (bl *Baseline) String() string {
var line strings.Builder
if bl.FrontURL != "" {

View File

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/chainreactors/logs"
"io/ioutil"
"strconv"
"strings"
@ -56,6 +57,21 @@ type Statistor struct {
RuleFilter string `json:"rule_filter"`
}
func (stat *Statistor) ColorString() string {
var s strings.Builder
s.WriteString(fmt.Sprintf("[stat] %s took %d s, request total: %s, finish: %s/%s, found: %s, check: %s, failed: %s", logs.GreenLine(stat.BaseUrl), stat.EndTime-stat.StartTime, logs.YellowBold(strconv.Itoa(int(stat.ReqTotal))), logs.YellowBold(strconv.Itoa(stat.End)), logs.YellowBold(strconv.Itoa(stat.Total)), logs.YellowBold(strconv.Itoa(stat.FoundNumber)), logs.YellowBold(strconv.Itoa(stat.CheckNumber)), logs.YellowBold(strconv.Itoa(int(stat.FailedNumber)))))
if stat.FuzzyNumber != 0 {
s.WriteString(", fuzzy: " + logs.Yellow(strconv.Itoa(stat.FuzzyNumber)))
}
if stat.FilteredNumber != 0 {
s.WriteString(", filtered: " + logs.Yellow(strconv.Itoa(stat.FilteredNumber)))
}
if stat.WafedNumber != 0 {
s.WriteString(", wafed: " + logs.Yellow(strconv.Itoa(stat.WafedNumber)))
}
return s.String()
}
func (stat *Statistor) String() string {
var s strings.Builder
s.WriteString(fmt.Sprintf("[stat] %s took %d s, request total: %d, finish: %d/%d, found: %d, check: %d, failed: %d", stat.BaseUrl, stat.EndTime-stat.StartTime, stat.ReqTotal, stat.End, stat.Total, stat.FoundNumber, stat.CheckNumber, stat.FailedNumber))
@ -85,6 +101,19 @@ func (stat *Statistor) Detail() string {
return s.String()
}
func (stat *Statistor) ColorDetail() string {
var s strings.Builder
s.WriteString("[stat] ")
s.WriteString(stat.BaseUrl)
for k, v := range stat.Counts {
if k == 0 {
continue
}
s.WriteString(fmt.Sprintf(" %s: %s,", logs.YellowBold(strconv.Itoa(k)), logs.YellowBold(strconv.Itoa(v))))
}
return s.String()
}
func (stat *Statistor) Json() string {
content, err := json.Marshal(stat)
if err != nil {