Skip to content

Commit

Permalink
Merge pull request #14 from C-Sto/better-ui
Browse files Browse the repository at this point in the history
Better ui
  • Loading branch information
C-Sto authored Oct 4, 2018
2 parents cde7814 + 46a6979 commit 671076e
Show file tree
Hide file tree
Showing 7 changed files with 343 additions and 155 deletions.
101 changes: 0 additions & 101 deletions TODO.md

This file was deleted.

18 changes: 17 additions & 1 deletion librecursebuster/ConsoleWriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ type ConsoleWriter struct {
}

//This is super stupid, I should use a lib for this

func (c *ConsoleWriter) formatHeader(buf *[]byte, t time.Time, file string, line int) {
*buf = append(*buf, c.prefix...)
year, month, day := t.Date()
Expand Down Expand Up @@ -61,6 +60,10 @@ func (ConsoleWriter) New(w io.Writer, prefix string) *ConsoleWriter {
return &ConsoleWriter{out: w, prefix: prefix, flag: 0, mu: m}
}

func (c ConsoleWriter) GetPrefix() string {
return c.prefix
}

// Output writes the output for an event. The string s contains
// the text to print after the prefix specified by the flags of the
// Logger. A newline is appended if the last character of s is not
Expand Down Expand Up @@ -97,3 +100,16 @@ func (c *ConsoleWriter) Printf(format string, v ...interface{}) {
fmt.Println(err)
}
}

func (c *ConsoleWriter) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
now := time.Now() // get this early.
var file string
var line int
c.mu.Lock()
defer c.mu.Unlock()
c.buf = c.buf[:0]
c.formatHeader(&c.buf, now, file, line)
c.buf = append(c.buf, fmt.Sprintf(format, a)...)
n, err = w.Write(c.buf)
return
}
67 changes: 36 additions & 31 deletions librecursebuster/logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,9 @@ func ManageRequests(cfg *Config, state *State, wg *sync.WaitGroup, pages, newPag
//ManageNewURLs will take in any URL, and decide if it should be added to the queue for bustin', or if we discovered something new
func ManageNewURLs(cfg *Config, state *State, wg *sync.WaitGroup, pages, newpages chan SpiderPage, printChan chan OutLine) {
//decides on whether to add to the directory list, or add to file output
checked := make(map[string]bool)
// preCheck := make(map[string]bool)
for {
candidate := <-newpages

/*//shortcut (will make checked much bigger than it should be, but will save cycles)
//removed due to stupid memory soaking issue
if _, ok := preCheck[candidate.URL]; ok {
wg.Done()
continue
}
preCheck[candidate.URL] = true
*/

//check the candidate is an actual URL
u, err := url.Parse(strings.TrimSpace(candidate.URL))

Expand All @@ -71,14 +60,15 @@ func ManageNewURLs(cfg *Config, state *State, wg *sync.WaitGroup, pages, newpage
//actualUrl := state.ParsedURL.Scheme + "://" + u.Host
actualURL := cleanURL(u, (*candidate.Reference).Scheme+"://"+u.Host)

if _, ok := checked[actualURL]; !ok && //must have not checked it before
state.CMut.Lock()
if _, ok := state.Checked[actualURL]; !ok && //must have not checked it before
(state.Hosts.HostExists(u.Host) || state.Whitelist[u.Host]) && //must be within whitelist, or be one of the starting urls
!cfg.NoRecursion { //no recursion means we don't care about adding extra paths or content

checked[actualURL] = true

state.Checked[actualURL] = true
state.CMut.Unlock()
wg.Add(1)
pages <- SpiderPage{URL: actualURL, Reference: candidate.Reference}
PrintOutput("URL Added: "+actualURL, Debug, 3, wg, printChan)

//also add any directories in the supplied path to the 'to be hacked' queue
path := ""
Expand All @@ -98,12 +88,17 @@ func ManageNewURLs(cfg *Config, state *State, wg *sync.WaitGroup, pages, newpage
newPage := SpiderPage{}
newPage.URL = newDir
newPage.Reference = candidate.Reference
if checked[actualURL] {
state.CMut.RLock()
if state.Checked[newDir] {
state.CMut.RUnlock()
continue
}
state.CMut.RUnlock()
wg.Add(1)
newpages <- newPage
}
} else {
state.CMut.Unlock()
}

wg.Done()
Expand Down Expand Up @@ -200,28 +195,38 @@ func dirBust(cfg *Config, state *State, page SpiderPage, wg *sync.WaitGroup, wor
if cfg.MaxDirs == 1 {
atomic.StoreUint32(state.DirbProgress, 0)
}
for word := range wordsChan { //will receive from the channel until it's closed
//read words off the channel, and test it
for _, method := range state.Methods {

if len(state.Extensions) > 0 && state.Extensions[0] != "" {
for _, ext := range state.Extensions {
for word := range wordsChan { //will receive from the channel until it's closed
//read words off the channel, and test it OR close out because we wanna skip it
select {
case <-state.StopDir:
<-maxDirs
if !cfg.NoStartStop {
PrintOutput(fmt.Sprintf("Finished dirbusting: %s", page.URL), Info, 0, wg, printChan)
}
return
default:
for _, method := range state.Methods {

if len(state.Extensions) > 0 && state.Extensions[0] != "" {
for _, ext := range state.Extensions {
workers <- struct{}{}
wg.Add(1)
go testURL(cfg, state, wg, method, page.URL+word+"."+ext, state.Client, newPages, workers, confirmed, printChan, testChan)
}
}
if cfg.AppendDir {
workers <- struct{}{}
wg.Add(1)
go testURL(cfg, state, wg, method, page.URL+word+"."+ext, state.Client, newPages, workers, confirmed, printChan, testChan)
go testURL(cfg, state, wg, method, page.URL+word+"/", state.Client, newPages, workers, confirmed, printChan, testChan)
}
}
if cfg.AppendDir {
workers <- struct{}{}
wg.Add(1)
go testURL(cfg, state, wg, method, page.URL+word+"/", state.Client, newPages, workers, confirmed, printChan, testChan)
}
workers <- struct{}{}
wg.Add(1)
go testURL(cfg, state, wg, method, page.URL+word, state.Client, newPages, workers, confirmed, printChan, testChan)
go testURL(cfg, state, wg, method, page.URL+word, state.Client, newPages, workers, confirmed, printChan, testChan)

if cfg.MaxDirs == 1 {
atomic.AddUint32(state.DirbProgress, 1)
if cfg.MaxDirs == 1 {
atomic.AddUint32(state.DirbProgress, 1)
}
}
}
}
Expand Down
99 changes: 86 additions & 13 deletions librecursebuster/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,23 @@ import (
"sync"
"sync/atomic"
"time"

"github.com/jroimartin/gocui"
)

//PrintBanner prints the banner and in debug mode will also print all set options
func PrintBanner(cfg *Config) {
//todo: include settings in banner
fmt.Println(strings.Repeat("=", 20))
fmt.Println("recursebuster V" + cfg.Version)
fmt.Println("Poorly hacked together by C_Sto (@C__Sto)")
fmt.Println("Heavy influence from Gograbber, thx Swarlz")
fmt.Println(strings.Repeat("=", 20))
if cfg.Debug {
printOpts(cfg)
if cfg.NoUI {
fmt.Println(strings.Repeat("=", 20))
fmt.Println("recursebuster V" + cfg.Version)
fmt.Println("Poorly hacked together by C_Sto (@C__Sto)")
fmt.Println("Heavy influence from Gograbber, thx Swarlz")
fmt.Println(strings.Repeat("=", 20))
if cfg.Debug {
printOpts(cfg)
fmt.Println(strings.Repeat("=", 20))
}
}
}

Expand Down Expand Up @@ -107,6 +111,59 @@ func PrintOutput(message string, writer *ConsoleWriter, verboseLevel int, wg *sy
}
}

func UIPrinter(cfg *Config, state *State, wg *sync.WaitGroup, printChan chan OutLine, testChan chan string) {
tick := time.NewTicker(time.Second * 2)
testedURL := ""
for {
select {
case o := <-printChan:
//something to print
//v.Write([]byte(o.Content + "\n"))
if cfg.VerboseLevel >= o.Level {
addToMainUI(state, o)
}
//state.ui.Update()
//fmt.Fprintln(v, o.Content+"\n")

case <-tick.C:
//time has elapsed the amount of time - it's been 2 seconds

case t := <-testChan:
//URL has been assessed
testedURL = t
}
writeStatus(state, testedURL)
}
}

func addToMainUI(state *State, o OutLine) { //s string) {
state.ui.Update(func(g *gocui.Gui) error {
v, err := g.View("Main")
if err != nil {
return err
}
fmt.Fprintln(v, o.Type.GetPrefix()+o.Content)
return nil
})
}

func writeStatus(state *State, s string) {
state.ui.Update(func(g *gocui.Gui) error {
v, err := g.View("Status")
if err != nil {
return err
// handle error
}
v.Clear()
fmt.Fprintln(v, getStatus(state))
sprint := fmt.Sprintf("[%.2f%%%%]%s", 100*float64(atomic.LoadUint32(state.DirbProgress))/float64(atomic.LoadUint32(state.WordlistLen)), s)
fmt.Fprintln(v, sprint)
fmt.Fprintln(v, "ctrl + [(c) quit, (x) stop current dir], (arrow up/down) move one line, (pgup/pgdown) move 10 lines")
fmt.Fprintln(v, time.Now().String())
return nil
})
}

//StatusPrinter is the function that performs all the status printing logic
func StatusPrinter(cfg *Config, state *State, wg *sync.WaitGroup, printChan chan OutLine, testChan chan string) {
tick := time.NewTicker(time.Second * 2)
Expand All @@ -117,13 +174,24 @@ func StatusPrinter(cfg *Config, state *State, wg *sync.WaitGroup, printChan chan
select {
case o := <-printChan:
//shoudln't need to check for status here..

//clear the line before printing anything
fmt.Printf("\r%s\r", strings.Repeat(" ", spacesToClear))
if cfg.NoUI {
fmt.Printf("\r%s\r", strings.Repeat(" ", spacesToClear))
}

if cfg.VerboseLevel >= o.Level {
o.Type.Println(o.Content)
//don't need to remember spaces to clear this line - this is newline suffixed
if cfg.NoUI {
o.Type.Println(o.Content)
//don't need to remember spaces to clear this line - this is newline suffixed
} else {
v, err := state.ui.View("Main")
if err != nil {
panic(err)
}
fmt.Fprintln(v, o.Content+"\n")
//v.Write([]byte(o.Content))
//o.Type.Fprintf(v, o.Content, nil...)
}
}
wg.Done()

Expand All @@ -135,9 +203,9 @@ func StatusPrinter(cfg *Config, state *State, wg *sync.WaitGroup, printChan chan
testedURL = t
}

if !cfg.NoStatus {
if !cfg.NoStatus && cfg.NoUI {
//assemble the status string
sprint := fmt.Sprintf("%s"+black.Sprintf(">"), status)
sprint := fmt.Sprintf("%s"+black.Sprint(">"), status)
if cfg.MaxDirs == 1 && cfg.Wordlist != "" {
//this is the grossest format string I ever did see
sprint += fmt.Sprintf("[%.2f%%%%]%s", 100*float64(atomic.LoadUint32(state.DirbProgress))/float64(atomic.LoadUint32(state.WordlistLen)), testedURL)
Expand All @@ -149,6 +217,11 @@ func StatusPrinter(cfg *Config, state *State, wg *sync.WaitGroup, printChan chan
fmt.Printf("\r%s\r", strings.Repeat(" ", spacesToClear))

Status.Printf(sprint + "\r")
/* v, err := state.ui.View("Main")
if err != nil {
panic(err)
}
fmt.Fprintln(v, sprint+"\n")*/
//remember how many spaces we need to use to clear the line (21 for the date and time prefix)
spacesToClear = len(sprint) + 21
}
Expand Down
Loading

0 comments on commit 671076e

Please sign in to comment.