Refactor code, add meaningful comments

dev
Manuel Bua 2020-07-11 22:57:44 +02:00
parent 002daadf46
commit 97901f36b4
6 changed files with 153 additions and 53 deletions

View File

@ -1,5 +1,9 @@
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
@ -24,6 +28,10 @@ github.com/karrick/godirwalk v1.15.6 h1:Yf2mmR8TJy+8Fa0SuQVto5SYap6IF7lNVX4Jdl8G
github.com/karrick/godirwalk v1.15.6/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
@ -42,6 +50,8 @@ github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/vbauerster/mpb/v5 v5.2.2 h1:zIICVOm+XD+uV6crpSORaL6I0Q1WqOdvxZTp+r3L9cw=
github.com/vbauerster/mpb/v5 v5.2.2/go.mod h1:W5Fvgw4dm3/0NhqzV8j6EacfuTe5SvnzBRwiXxDR9ww=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -57,8 +67,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
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-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -0,0 +1,27 @@
package progress
import (
"github.com/vbauerster/mpb/v5"
"sync/atomic"
)
// Represents a single progress bar
type Bar struct {
bar *mpb.Bar
total int64
initialTotal int64
}
// Drops the specified number of requests from the progress bar total.
// This may be the case when uncompleted requests are encountered and shouldn't be part of the total count.
func (b *Bar) Drop(count int64) {
atomic.AddInt64(&b.total, -count)
b.bar.SetTotal(atomic.LoadInt64(&b.total), false)
}
// Ensures that a progress bar's total count is up-to-date if during an enumeration there were uncompleted requests.
func (b *Bar) finish() {
if b.initialTotal != b.total {
b.bar.SetTotal(b.total, true)
}
}

View File

@ -0,0 +1,2 @@
// Tracks enumeration progress information and implements visible tracking with one or more progress bars.
package progress

View File

@ -9,14 +9,14 @@ import (
"os"
"strings"
"sync"
"sync/atomic"
)
// Encapsulates progress tracking.
type Progress struct {
progress *mpb.Progress
bar *mpb.Bar
total int64
initialTotal int64
progress *mpb.Progress
barTemplate *Bar
barGlobal *Bar
captureData *captureData
termWidth int
stdCaptureMutex *sync.Mutex
@ -24,6 +24,7 @@ type Progress struct {
stderr *strings.Builder
}
// Creates and returns a new progress tracking object.
func NewProgress(group *sync.WaitGroup) *Progress {
w := cwriter.New(os.Stderr)
tw, err := w.GetWidth()
@ -45,54 +46,110 @@ func NewProgress(group *sync.WaitGroup) *Progress {
return p
}
func (p *Progress) SetupProgressBar(name string, total int64) *mpb.Bar {
barname := "[" + aurora.Green(name).String() + "]"
bar := p.progress.AddBar(
// Creates and returns a progress bar that tracks request progress for a specific template.
func (p *Progress) SetupTemplateProgressbar(templateIndex int, templateCount int, name string, requestCount int64) {
barName := "[" + aurora.Green(name).String() + "]"
if templateIndex > -1 && templateCount > -1 {
barName = aurora.Sprintf("[%d/%d] ", aurora.Bold(aurora.Cyan(templateIndex)), aurora.Cyan(templateCount)) + barName
}
bar := p.setupProgressbar(barName, requestCount)
if p.barTemplate != nil {
// ensure any previous bar has finished and aborted requests have also been considered
p.barTemplate.finish()
}
p.barTemplate = &Bar{
bar: bar,
total: requestCount,
initialTotal: requestCount,
}
}
// Creates and returns a progress bar that tracks all the requests progress.
// This is only useful when multiple templates are processed within the same run.
func (p *Progress) SetupGlobalProgressbar(hostCount int64, templateCount int, requestCount int64) {
hostPlural := "host"
if hostCount > 1 {
hostPlural = "hosts"
}
barName := "[" + aurora.Sprintf(
aurora.Cyan("%d templates, %d %s"),
aurora.Bold(aurora.Cyan(templateCount)),
aurora.Bold(aurora.Cyan(hostCount)),
hostPlural) + "]"
bar := p.setupProgressbar(barName, requestCount)
p.barGlobal = &Bar{
bar: bar,
total: requestCount,
initialTotal: requestCount,
}
}
// Update progress tracking information and increments the request counter by one unit.
// If a global progress bar is present it will be updated as well.
func (p *Progress) Update() {
p.barTemplate.bar.Increment()
if p.barGlobal != nil {
p.barGlobal.bar.Increment()
}
}
// Drops the specified number of requests from the progress bar total.
// This may be the case when uncompleted requests are encountered and shouldn't be part of the total count.
// If a global progress bar is present it will be updated as well.
func (p *Progress) Drop(count int64) {
p.barTemplate.Drop(count)
if p.barGlobal != nil {
p.barGlobal.Drop(count)
}
}
// Ensures that a progress bar's total count is up-to-date if during an enumeration there were uncompleted requests and
// wait for all the progress bars to finish.
// If a global progress bar is present it will be updated as well.
func (p *Progress) Wait() {
p.barTemplate.finish()
if p.barGlobal != nil {
p.barGlobal.finish()
}
p.progress.Wait()
}
// Creates and returns a progress bar.
func (p *Progress) setupProgressbar(name string, total int64) *mpb.Bar {
return p.progress.AddBar(
total,
mpb.BarNoPop(),
mpb.BarRemoveOnComplete(),
mpb.PrependDecorators(
decor.Name(barname),
decor.CountersNoUnit(aurora.Blue(" %d/%d").String()),
decor.Name(name, decor.WCSyncSpaceR),
decor.CountersNoUnit(aurora.Blue(" %d/%d").String(), decor.WCSyncSpace),
decor.NewPercentage(aurora.Bold("%d").String(), decor.WCSyncSpace),
),
mpb.AppendDecorators(
decor.AverageSpeed(0, aurora.Yellow("%.2f req/s ").String()),
decor.OnComplete(
decor.AverageETA(decor.ET_STYLE_GO), aurora.Bold("done!").String(),
),
decor.AverageSpeed(0, aurora.Yellow("%.2f r/s ").String(), decor.WCSyncSpace),
decor.AverageETA(decor.ET_STYLE_GO, decor.WCSyncSpace),
),
)
p.bar = bar
p.total = total
p.initialTotal = total
return bar
}
func (p *Progress) Update() {
p.bar.Increment()
}
func (p *Progress) Abort(remaining int64) {
atomic.AddInt64(&p.total, -remaining)
p.bar.SetTotal(atomic.LoadInt64(&p.total), false)
}
func (p *Progress) Wait() {
if p.initialTotal != p.total {
p.bar.SetTotal(p.total, true)
}
p.progress.Wait()
}
//
// Starts capturing stdout and stderr instead of producing visual output that may interfere with the progress bars.
func (p *Progress) StartStdCapture() {
p.stdCaptureMutex.Lock()
p.captureData = startStdCapture()
}
// Stops capturing stdout and stderr and store both output to be shown later.
func (p *Progress) StopStdCapture() {
stopStdCapture(p.captureData)
p.stdout.Write(p.captureData.DataStdOut.Bytes())
@ -100,12 +157,14 @@ func (p *Progress) StopStdCapture() {
p.stdCaptureMutex.Unlock()
}
// Writes the captured stdout data to stdout, if any.
func (p *Progress) ShowStdOut() {
if p.stdout.Len() > 0 {
fmt.Fprint(os.Stdout, p.stdout.String())
}
}
// Writes the captured stderr data to stderr, if any.
func (p *Progress) ShowStdErr() {
if p.stderr.Len() > 0 {
fmt.Fprint(os.Stderr, p.stderr.String())

View File

@ -137,7 +137,7 @@ func (r *Runner) RunEnumeration() {
var results bool
template := t.(*templates.Template)
p.SetupProgressBar(template.ID, r.inputCount * template.GetHTTPRequestsCount())
p.SetupTemplateProgressbar(-1, -1, template.ID, r.inputCount * template.GetHTTPRequestsCount())
// process http requests
for _, request := range template.RequestsHTTP {
@ -197,11 +197,9 @@ func (r *Runner) RunEnumeration() {
gologger.Fatalf("Error, no templates found in directory: '%s'\n", r.options.Templates)
}
// track progress
p := progress.NewProgress(nil)
// precompute request count
var totalRequests int64 = 0
var totalTemplates int = len(matches)
for _, match := range matches {
t, err := r.parse(match)
switch t.(type) {
@ -209,20 +207,23 @@ func (r *Runner) RunEnumeration() {
template := t.(*templates.Template)
totalRequests += template.GetHTTPRequestsCount()
default:
p.StartStdCapture()
gologger.Errorf("Could not parse file '%s': %s\n", r.options.Templates, err)
p.StopStdCapture()
}
}
p.SetupProgressBar("Multiple templates", r.inputCount * totalRequests)
// track progress
p := progress.NewProgress(nil)
p.SetupGlobalProgressbar(r.inputCount, len(matches), r.inputCount * totalRequests)
var results bool
for _, match := range matches {
for i, match := range matches {
t, err := r.parse(match)
switch t.(type) {
case *templates.Template:
template := t.(*templates.Template)
p.SetupTemplateProgressbar(i, totalTemplates, template.ID, r.inputCount * template.GetHTTPRequestsCount())
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateWithList(p, template, request)
if dnsResults {
@ -256,9 +257,7 @@ func (r *Runner) RunEnumeration() {
r.output.Close()
os.Remove(outputFile)
}
//p.StartStdCapture()
gologger.Infof("No results found for the template. Happy hacking!")
//p.StopStdCapture()
}
return

View File

@ -106,7 +106,7 @@ func (e *HTTPExecutor) ExecuteHTTP(p *progress.Progress, URL string) error {
mainLoop:
for compiledRequest := range compiledRequest {
if compiledRequest.Error != nil {
p.Abort(remaining)
p.Drop(remaining)
return errors.Wrap(err, "error in compiled http request")
}
e.setCustomHeaders(compiledRequest)
@ -115,7 +115,7 @@ mainLoop:
if e.debug {
dumpedRequest, err := httputil.DumpRequest(req.Request, true)
if err != nil {
p.Abort(remaining)
p.Drop(remaining)
return errors.Wrap(err, "could not dump http request")
}
p.StartStdCapture()
@ -129,7 +129,7 @@ mainLoop:
if resp != nil {
resp.Body.Close()
}
p.Abort(1)
p.Drop(1)
p.StartStdCapture()
gologger.Warningf("Could not do request: %s\n", err)
p.StopStdCapture()
@ -139,7 +139,7 @@ mainLoop:
if e.debug {
dumpedResponse, err := httputil.DumpResponse(resp, true)
if err != nil {
p.Abort(remaining)
p.Drop(remaining)
return errors.Wrap(err, "could not dump http response")
}
p.StartStdCapture()
@ -152,7 +152,7 @@ mainLoop:
if err != nil {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
p.Abort(remaining)
p.Drop(remaining)
return errors.Wrap(err, "could not read http body")
}
resp.Body.Close()
@ -161,7 +161,7 @@ mainLoop:
// so in case we have to manually do it
data, err = requests.HandleDecompression(compiledRequest.Request, data)
if err != nil {
p.Abort(remaining)
p.Drop(remaining)
return errors.Wrap(err, "could not decompress http body")
}