Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better ui #14

Merged
merged 11 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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