diff --git a/modules/net_recon.go b/modules/net_recon.go index e9a5d95c..01ef171a 100644 --- a/modules/net_recon.go +++ b/modules/net_recon.go @@ -46,7 +46,7 @@ func NewDiscovery(s *session.Session) *Discovery { return d.Show(args[0]) })) - d.selector = ViewSelectorFor(&d.SessionModule, "net.show", []string{"ip", "mac", "seen", "sent", "rcvd"}, "") + d.selector = ViewSelectorFor(&d.SessionModule, "net.show", []string{"ip", "mac", "seen", "sent", "rcvd"}, "ip asc") return d } diff --git a/modules/net_show.go b/modules/net_show.go index 8cd9f63d..b7cd5fcc 100644 --- a/modules/net_show.go +++ b/modules/net_show.go @@ -143,7 +143,7 @@ func (d *Discovery) doSelection(arg string) (err error, targets []*network.Endpo } targets = filtered - switch d.selector.SortBy { + switch d.selector.SortField { case "ip": sort.Sort(ByIpSorter(targets)) case "mac": @@ -185,25 +185,17 @@ func (d *Discovery) colNames(hasMeta bool) []string { colNames = append(colNames, "Meta") } - dir := tui.Blue("▾") - if d.selector.Sort == "asc" { - dir = tui.Blue("▴") - } - - if d.selector.SortBy == "" { - d.selector.SortBy = "ip" - } - switch d.selector.SortBy { + switch d.selector.SortField { case "mac": - colNames[1] += " " + dir + colNames[1] += " " + d.selector.SortSymbol case "sent": - colNames[4] += " " + dir + colNames[4] += " " + d.selector.SortSymbol case "rcvd": - colNames[5] += " " + dir + colNames[5] += " " + d.selector.SortSymbol case "seen": - colNames[6] += " " + dir + colNames[6] += " " + d.selector.SortSymbol case "ip": - colNames[0] += " " + dir + colNames[0] += " " + d.selector.SortSymbol } return colNames diff --git a/modules/view_selector.go b/modules/view_selector.go index 008b438d..a5e0a745 100644 --- a/modules/view_selector.go +++ b/modules/view_selector.go @@ -2,10 +2,13 @@ package modules import ( "fmt" + "regexp" "strings" "github.com/bettercap/bettercap/session" + + "github.com/evilsocket/islazy/tui" ) type ViewSelector struct { @@ -16,46 +19,44 @@ type ViewSelector struct { filterPrev string Expression *regexp.Regexp - SortBy string - sortBys map[string]bool - sortByName string - - Sort string - sortName string + SortField string + Sort string + SortSymbol string + sortFields map[string]bool + sortName string + sortParser string + sortParse *regexp.Regexp Limit int limitName string } -func ViewSelectorFor(m *session.SessionModule, prefix string, sortBys []string, defSortBy string) *ViewSelector { +func ViewSelectorFor(m *session.SessionModule, prefix string, sortFields []string, defExpression string) *ViewSelector { + parser := "(" + strings.Join(sortFields, "|") + ") (desc|asc)" s := &ViewSelector{ owner: m, filterName: prefix + ".filter", - filterPrev: "", - sortByName: prefix + ".sort_by", - sortBys: make(map[string]bool), sortName: prefix + ".sort", + sortParser: parser, + sortParse: regexp.MustCompile(parser), limitName: prefix + ".limit", - - SortBy: defSortBy, - Sort: "asc", - Limit: 0, - Filter: "", - Expression: nil, - } - - for _, sb := range sortBys { - s.sortBys[sb] = true } m.AddParam(session.NewStringParameter(s.filterName, "", "", "Defines a regular expression filter for "+prefix)) - m.AddParam(session.NewStringParameter(s.sortByName, defSortBy, "", "Defines sorting field for "+prefix+", available: "+strings.Join(sortBys, ", "))) - m.AddParam(session.NewStringParameter(s.sortName, "asc", "", "Defines sorting direction for "+prefix)) + m.AddParam(session.NewStringParameter( + s.sortName, + defExpression, + s.sortParser, + "Defines sorting field ("+strings.Join(sortFields, ", ")+") and direction (asc or desc) for "+prefix)) + m.AddParam(session.NewIntParameter(s.limitName, "0", "Defines limit for "+prefix)) + + s.parseSorting() + return s } -func (s *ViewSelector) Update() (err error) { +func (s *ViewSelector) parseFilter() (err error) { if err, s.Filter = s.owner.StringParam(s.filterName); err != nil { return } @@ -70,24 +71,37 @@ func (s *ViewSelector) Update() (err error) { s.Expression = nil } s.filterPrev = s.Filter + return +} - if err, s.SortBy = s.owner.StringParam(s.sortByName); err != nil { +func (s *ViewSelector) parseSorting() (err error) { + expr := "" + if err, expr = s.owner.StringParam(s.sortName); err != nil { return - } else if s.SortBy != "" { - if _, found := s.sortBys[s.SortBy]; !found { - return fmt.Errorf("'%s' is not valid for %s", s.SortBy, s.sortByName) - } } - if err, s.Sort = s.owner.StringParam(s.sortName); err != nil { - return - } else if s.Sort != "asc" && s.Sort != "desc" { - return fmt.Errorf("'%s' is not valid for %s", s.Sort, s.sortName) + tokens := s.sortParse.FindAllStringSubmatch(expr, -1) + if tokens == nil { + return fmt.Errorf("expression '%s' doesn't parse", expr) } - if err, s.Limit = s.owner.IntParam(s.limitName); err != nil { - return + s.SortField = tokens[0][1] + s.Sort = tokens[0][2] + s.SortSymbol = tui.Blue("▾") + if s.Sort == "asc" { + s.SortSymbol = tui.Blue("▴") } return } + +func (s *ViewSelector) Update() (err error) { + if err = s.parseFilter(); err != nil { + return + } else if err = s.parseSorting(); err != nil { + return + } else if err, s.Limit = s.owner.IntParam(s.limitName); err != nil { + return + } + return +} diff --git a/modules/wifi.go b/modules/wifi.go index 68c0cbbf..20f87868 100644 --- a/modules/wifi.go +++ b/modules/wifi.go @@ -148,7 +148,7 @@ func NewWiFiModule(s *session.Session) *WiFiModule { })) w.selector = ViewSelectorFor(&w.SessionModule, "wifi.show", - []string{"rssi", "bssid", "essid", "channel", "encryption", "clients", "seen", "sent", "rcvd"}, "rssi") + []string{"rssi", "bssid", "essid", "channel", "encryption", "clients", "seen", "sent", "rcvd"}, "rssi asc") w.AddHandler(session.NewModuleHandler("wifi.recon.channel", `wifi\.recon\.channel[\s]+([0-9]+(?:[, ]+[0-9]+)*|clear)`, "WiFi channels (comma separated) or 'clear' for channel hopping.", diff --git a/modules/wifi_show.go b/modules/wifi_show.go index 9839901a..ee51f35a 100644 --- a/modules/wifi_show.go +++ b/modules/wifi_show.go @@ -146,7 +146,7 @@ func (w *WiFiModule) doSelection() (err error, stations []*network.Station) { } stations = filtered - switch w.selector.SortBy { + switch w.selector.SortField { case "seen": sort.Sort(ByWiFiSeenSorter(stations)) case "essid": @@ -211,33 +211,25 @@ func (w *WiFiModule) colNames(nrows int) []string { } if columns != nil { - dir := tui.Blue("▾") - if w.selector.Sort == "asc" { - dir = tui.Blue("▴") - } - - if w.selector.SortBy == "" { - w.selector.SortBy = "rssi" - } - switch w.selector.SortBy { + switch w.selector.SortField { case "seen": - w.colDecorate(columns, "Last Seen", dir) + w.colDecorate(columns, "Last Seen", w.selector.SortSymbol) case "essid": - w.colDecorate(columns, "SSID", dir) + w.colDecorate(columns, "SSID", w.selector.SortSymbol) case "bssid": - w.colDecorate(columns, "BSSID", dir) + w.colDecorate(columns, "BSSID", w.selector.SortSymbol) case "channel": - w.colDecorate(columns, "Channel", dir) + w.colDecorate(columns, "Channel", w.selector.SortSymbol) case "clients": - w.colDecorate(columns, "Clients", dir) + w.colDecorate(columns, "Clients", w.selector.SortSymbol) case "encryption": - w.colDecorate(columns, "Encryption", dir) + w.colDecorate(columns, "Encryption", w.selector.SortSymbol) case "sent": - w.colDecorate(columns, "Sent", dir) + w.colDecorate(columns, "Sent", w.selector.SortSymbol) case "rcvd": - w.colDecorate(columns, "Recvd", dir) + w.colDecorate(columns, "Recvd", w.selector.SortSymbol) case "rssi": - w.colDecorate(columns, "RSSI", dir) + w.colDecorate(columns, "RSSI", w.selector.SortSymbol) } }