diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go index 8812b9d9..04f84e78 100644 --- a/v2/cmd/nuclei/main.go +++ b/v2/cmd/nuclei/main.go @@ -310,6 +310,7 @@ on extensive configurability, massive extensibility and ease of use.`) flagSet.StringVarP(&options.GetTemplate, "get-template", "gtm", "", "get template content by id"), flagSet.BoolVarP(&options.NoStore, "no-store", "nos", false, "disable scan/output storage on cloud"), flagSet.StringVarP(&options.ScanOutput, "scan-output", "sno", "", "display scan output by scan id"), + flagSet.BoolVar(&options.NoTables, "no-tables", false, "do not display pretty-printed tables"), flagSet.IntVar(&options.OutputLimit, "limit", 100, "limit the number of output to display"), ) diff --git a/v2/go.mod b/v2/go.mod index 2ac3c442..6de38db8 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -78,7 +78,7 @@ require ( github.com/projectdiscovery/ratelimit v0.0.2 github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 github.com/projectdiscovery/sarif v0.0.1 - github.com/projectdiscovery/tlsx v0.0.10-0.20221214133108-b1c80ad6876e + github.com/projectdiscovery/tlsx v1.0.0 github.com/projectdiscovery/uncover v1.0.1 github.com/projectdiscovery/utils v0.0.4-0.20221201124851-f8524345b6d3 github.com/projectdiscovery/wappalyzergo v0.0.73 diff --git a/v2/go.sum b/v2/go.sum index 3f956874..e0bd5b15 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -575,8 +575,6 @@ github.com/projectdiscovery/sliceutil v0.0.1/go.mod h1:0wBmhU5uTDwMfrEZfvwH9qa5k github.com/projectdiscovery/stringsutil v0.0.0-20220208075244-7c05502ca8e9/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I= github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA= github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0= -github.com/projectdiscovery/tlsx v0.0.10-0.20221214133108-b1c80ad6876e h1:hEZVGt0VriAqweU8wHHTY+fLuGC7GMEz8xUhseJgl6A= -github.com/projectdiscovery/tlsx v0.0.10-0.20221214133108-b1c80ad6876e/go.mod h1:LOgQpCTE96d/18+Zwu8p5b8ujOGPn6lIDqMIQCJHoXM= github.com/projectdiscovery/tlsx v1.0.0 h1:krS0QRbh4wHqeOybVQwBImY9PmIqzFOYM9Q+cKlEiZE= github.com/projectdiscovery/tlsx v1.0.0/go.mod h1:LOgQpCTE96d/18+Zwu8p5b8ujOGPn6lIDqMIQCJHoXM= github.com/projectdiscovery/uncover v1.0.1 h1:bhP+EW4d+e4cAizOWAEz7jeyKZGkDYYTsZlXsd11t+w= diff --git a/v2/internal/runner/cloud.go b/v2/internal/runner/cloud.go index 5aafd9c1..1b78c979 100644 --- a/v2/internal/runner/cloud.go +++ b/v2/internal/runner/cloud.go @@ -9,6 +9,7 @@ import ( "strings" jsoniter "github.com/json-iterator/go" + "github.com/olekukonko/tablewriter" "github.com/pkg/errors" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v2/internal/runner/nucleicloud" @@ -17,8 +18,10 @@ import ( // Get all the scan lists for a user/apikey. func (r *Runner) getScanList(limit int) error { - lastTime := "2099-01-02 15:04:05 +0000 UTC" + lastTime := "2099-01-02 1 5:04:05 +0000 UTC" + header := []string{"ID", "Timestamp", "Status", "Matched", "Targets", "Templates", "Duration"} + var values [][]string var count int var e error for { @@ -36,6 +39,8 @@ func (r *Runner) getScanList(limit int) error { res := nucleicloud.PrepareScanListOutput(v) if r.options.JSON { _ = jsoniter.NewEncoder(os.Stdout).Encode(res) + } else if !r.options.NoTables { + values = append(values, []string{strconv.FormatInt(res.ScanID, 10), res.Timestamp, strings.ToUpper(res.ScanStatus), strconv.Itoa(res.ScanResult), strconv.Itoa(res.Target), strconv.Itoa(res.Template), res.ScanTime}) } else { gologger.Silent().Msgf("%d. [%s] [STATUS: %s] [MATCHED: %d] [TARGETS: %d] [TEMPLATES: %d] [DURATION: %s]\n", res.ScanID, res.Timestamp, strings.ToUpper(res.ScanStatus), res.ScanResult, res.Target, res.Template, res.ScanTime) } @@ -44,9 +49,97 @@ func (r *Runner) getScanList(limit int) error { if count == 0 { return errors.New("no scan list found") } + if !r.options.NoTables { + r.prettyPrintTable(header, values) + } return e } +func (r *Runner) listDatasources() error { + datasources, err := r.cloudClient.ListDatasources() + if err != nil { + return err + } + if len(datasources) == 0 { + return errors.New("no cloud datasource list found") + } + + header := []string{"ID", "UpdatedAt", "Type", "Repo", "Path"} + var values [][]string + for _, source := range datasources { + if r.options.JSON { + _ = jsoniter.NewEncoder(os.Stdout).Encode(source) + } else if !r.options.NoTables { + values = append(values, []string{strconv.FormatInt(source.ID, 10), source.Updatedat.Format(nucleicloud.DDMMYYYYhhmmss), source.Type, source.Repo, source.Path}) + } else { + gologger.Silent().Msgf("%d. [%s] [%s] [%s] %s", source.ID, source.Updatedat.Format(nucleicloud.DDMMYYYYhhmmss), source.Type, source.Repo, source.Path) + } + } + if !r.options.NoTables { + r.prettyPrintTable(header, values) + } + return err +} + +func (r *Runner) listTargets() error { + items, err := r.cloudClient.ListTargets("") + if err != nil { + return err + } + if len(items) == 0 { + return errors.New("no target list found") + } + + header := []string{"ID", "Reference", "Count"} + var values [][]string + for _, source := range items { + if r.options.JSON { + _ = jsoniter.NewEncoder(os.Stdout).Encode(source) + } else if !r.options.NoTables { + values = append(values, []string{strconv.FormatInt(source.ID, 10), source.Reference, strconv.FormatInt(source.Count, 10)}) + } else { + gologger.Silent().Msgf("%d. %s (%d)", source.ID, source.Reference, source.Count) + } + } + if !r.options.NoTables { + r.prettyPrintTable(header, values) + } + return err +} + +func (r *Runner) listTemplates() error { + items, err := r.cloudClient.ListTemplates("") + if err != nil { + return err + } + if len(items) == 0 { + return errors.New("no template list found") + } + + header := []string{"ID", "Reference"} + var values [][]string + for _, source := range items { + if r.options.JSON { + _ = jsoniter.NewEncoder(os.Stdout).Encode(source) + } else if !r.options.NoTables { + values = append(values, []string{strconv.FormatInt(source.ID, 10), source.Reference}) + } else { + gologger.Silent().Msgf("%d. %s", source.ID, source.Reference) + } + } + if !r.options.NoTables { + r.prettyPrintTable(header, values) + } + return err +} + +func (r *Runner) prettyPrintTable(header []string, values [][]string) { + writer := tablewriter.NewWriter(os.Stdout) + writer.SetHeader(header) + writer.AppendBulk(values) + writer.Render() +} + func (r *Runner) deleteScan(id string) error { ID, _ := strconv.ParseInt(id, 10, 64) deleted, err := r.cloudClient.DeleteScan(ID) @@ -92,60 +185,6 @@ func (r *Runner) getTemplate(id string) error { return err } -func (r *Runner) listDatasources() error { - datasources, err := r.cloudClient.ListDatasources() - if err != nil { - return err - } - if len(datasources) == 0 { - return errors.New("no cloud datasource list found") - } - for _, source := range datasources { - if r.options.JSON { - _ = jsoniter.NewEncoder(os.Stdout).Encode(source) - } else { - gologger.Silent().Msgf("%d. [%s] [%s] [%s] %s", source.ID, source.Updatedat.Format(nucleicloud.DDMMYYYYhhmmss), source.Type, source.Repo, source.Path) - } - } - return err -} - -func (r *Runner) listTargets() error { - items, err := r.cloudClient.ListTargets("") - if err != nil { - return err - } - if len(items) == 0 { - return errors.New("no target list found") - } - for _, source := range items { - if r.options.JSON { - _ = jsoniter.NewEncoder(os.Stdout).Encode(source) - } else { - gologger.Silent().Msgf("%d. %s (%d)", source.ID, source.Reference, source.Count) - } - } - return err -} - -func (r *Runner) listTemplates() error { - items, err := r.cloudClient.ListTemplates("") - if err != nil { - return err - } - if len(items) == 0 { - return errors.New("no template list found") - } - for _, source := range items { - if r.options.JSON { - _ = jsoniter.NewEncoder(os.Stdout).Encode(source) - } else { - gologger.Silent().Msgf("%d. %s", source.ID, source.Reference) - } - } - return err -} - func (r *Runner) removeDatasource(datasource string) error { var source string ID, parseErr := strconv.ParseInt(datasource, 10, 64) diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go index 9f79021a..3866df76 100644 --- a/v2/pkg/types/types.go +++ b/v2/pkg/types/types.go @@ -181,6 +181,8 @@ type Options struct { Headless bool // ShowBrowser specifies whether the show the browser in headless mode ShowBrowser bool + // NoTables disables pretty printing of cloud results in tables + NoTables bool // DisableClustering disables clustering of templates DisableClustering bool // UseInstalledChrome skips chrome install and use local instance