diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/breachforum.go | 24 | ||||
| -rw-r--r-- | cmd/bssid.go | 30 | ||||
| -rw-r--r-- | cmd/crawl.go | 16 | ||||
| -rw-r--r-- | cmd/dns.go | 77 | ||||
| -rw-r--r-- | cmd/email.go | 24 | ||||
| -rw-r--r-- | cmd/files.go | 36 | ||||
| -rw-r--r-- | cmd/moon.go | 68 | ||||
| -rw-r--r-- | cmd/root.go | 2 | ||||
| -rw-r--r-- | cmd/sl.go | 13 | ||||
| -rw-r--r-- | cmd/stdin.go | 98 | ||||
| -rw-r--r-- | cmd/telegram.go | 24 | ||||
| -rw-r--r-- | cmd/username.go | 45 |
12 files changed, 283 insertions, 174 deletions
diff --git a/cmd/breachforum.go b/cmd/breachforum.go index 63254c1..229292a 100644 --- a/cmd/breachforum.go +++ b/cmd/breachforum.go @@ -11,7 +11,7 @@ var breachforumCmd = &cobra.Command{ Aliases: []string{"brf"}, Short: "Search BreachForum data", Long: `Search breachdetect index for BreachForum messages and detections`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runBreachForumSearch, } @@ -26,15 +26,17 @@ func runBreachForumSearch(cmd *cobra.Command, args []string) error { return err } - params := &models.BreachForumSearchParams{ - Search: args[0], - } - params.MaxHits, _ = cmd.Flags().GetInt("max_hits") - - response, err := c.SearchBreachForum(params) - if err != nil { - return err - } + maxHits, _ := cmd.Flags().GetInt("max_hits") - return formatter.FormatBreachForumResults(response, IsJSONOutput()) + return forEachQuery(args, func(query string) error { + params := &models.BreachForumSearchParams{ + Search: query, + MaxHits: maxHits, + } + response, err := c.SearchBreachForum(params) + if err != nil { + return err + } + return formatter.FormatBreachForumResults(response, IsJSONOutput()) + }) } diff --git a/cmd/bssid.go b/cmd/bssid.go index 0cf751f..116c63a 100644 --- a/cmd/bssid.go +++ b/cmd/bssid.go @@ -11,7 +11,7 @@ var bssidCmd = &cobra.Command{ Aliases: []string{"bs"}, Short: "Lookup WiFi access point location by BSSID", Long: `Lookup geographic location of a WiFi access point by its BSSID (MAC address) using Apple's location services`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runBSSIDLookup, } @@ -28,17 +28,21 @@ func runBSSIDLookup(cmd *cobra.Command, args []string) error { return err } - params := &models.BSSIDParams{ - BSSID: args[0], - } - params.All, _ = cmd.Flags().GetBool("all") - params.Google, _ = cmd.Flags().GetBool("google") - params.OSM, _ = cmd.Flags().GetBool("osm") - - response, err := c.LookupBSSID(params) - if err != nil { - return err - } + all, _ := cmd.Flags().GetBool("all") + google, _ := cmd.Flags().GetBool("google") + osm, _ := cmd.Flags().GetBool("osm") - return formatter.FormatBSSIDResults(*response, IsJSONOutput()) + return forEachQuery(args, func(bssid string) error { + params := &models.BSSIDParams{ + BSSID: bssid, + All: all, + Google: google, + OSM: osm, + } + response, err := c.LookupBSSID(params) + if err != nil { + return err + } + return formatter.FormatBSSIDResults(*response, IsJSONOutput()) + }) } diff --git a/cmd/crawl.go b/cmd/crawl.go index 2c9b719..5c5f78f 100644 --- a/cmd/crawl.go +++ b/cmd/crawl.go @@ -11,7 +11,7 @@ var crawlCmd = &cobra.Command{ Aliases: []string{"cw"}, Short: "Crawl domain", Long: `Resolves a domain using httpx and crawls it using katana. Returns discovered links as plain text, one per line, streamed in real-time. Supports both http:// and https:// URLs.`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runCrawl, } @@ -28,14 +28,10 @@ func runCrawl(cmd *cobra.Command, args []string) error { return err } - err = c.CrawlDomain(args[0], subdomains, func(line string) error { - fmt.Println(line) - return nil + return forEachQuery(args, func(domain string) error { + return c.CrawlDomain(domain, subdomains, func(line string) error { + fmt.Println(line) + return nil + }) }) - - if err != nil { - return err - } - - return nil } @@ -20,7 +20,7 @@ var dnsTLDCmd = &cobra.Command{ Aliases: []string{"t"}, Short: "Check NXDOMAIN for custom term against all TLDs", Long: "Streams NDJSON results checking each TLD. For NXDOMAIN domains, returns status. For existing domains, runs httpx to get page title and tech stack.", - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runDNSTLDCheck, } @@ -29,12 +29,11 @@ var dnsSiteCmd = &cobra.Command{ Aliases: []string{"s"}, Short: "Check if a website URL has been reused", Long: "Checks if a website URL has been reused across different domains", - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runDNSSiteCheck, } func runDNSTLDCheck(cmd *cobra.Command, args []string) error { - term := args[0] showOnly, _ := cmd.Flags().GetString("show-only") c, err := newUnauthenticatedClient() @@ -42,58 +41,54 @@ func runDNSTLDCheck(cmd *cobra.Command, args []string) error { return fmt.Errorf("failed to create client: %w", err) } - params := &models.DNSTLDParams{ - Term: term, - ShowOnly: showOnly, - } - - fmt.Printf("Checking TLDs for term: %s\n\n", term) - - err = c.CheckDNSTLDStream(params, func(result json.RawMessage) error { - var domainResult models.DomainResult - if err := json.Unmarshal(result, &domainResult); err != nil { - return fmt.Errorf("failed to parse result: %w", err) + return forEachQuery(args, func(term string) error { + params := &models.DNSTLDParams{ + Term: term, + ShowOnly: showOnly, } - output, err := formatter.FormatDNSResults(&domainResult, IsJSONOutput()) + fmt.Printf("Checking TLDs for term: %s\n\n", term) + + err := c.CheckDNSTLDStream(params, func(result json.RawMessage) error { + var domainResult models.DomainResult + if err := json.Unmarshal(result, &domainResult); err != nil { + return fmt.Errorf("failed to parse result: %w", err) + } + output, err := formatter.FormatDNSResults(&domainResult, IsJSONOutput()) + if err != nil { + return err + } + printOutput(output) + return nil + }) if err != nil { - return err + return fmt.Errorf("TLD check failed: %w", err) } - printOutput(output) return nil }) - - if err != nil { - return fmt.Errorf("TLD check failed: %w", err) - } - - return nil } func runDNSSiteCheck(cmd *cobra.Command, args []string) error { - siteURL := args[0] - c, err := newClient() if err != nil { return fmt.Errorf("failed to create client: %w", err) } - response, err := c.CheckDNSSite(siteURL) - if err != nil { - return fmt.Errorf("site check failed: %w", err) - } - - if err := checkError(response.Error); err != nil { - return err - } - - output, err := formatter.FormatDNSSite(response, IsJSONOutput()) - if err != nil { - return err - } - - printOutput(output) - return nil + return forEachQuery(args, func(siteURL string) error { + response, err := c.CheckDNSSite(siteURL) + if err != nil { + return fmt.Errorf("site check failed: %w", err) + } + if err := checkError(response.Error); err != nil { + return err + } + output, err := formatter.FormatDNSSite(response, IsJSONOutput()) + if err != nil { + return err + } + printOutput(output) + return nil + }) } func init() { diff --git a/cmd/email.go b/cmd/email.go index 85cc686..871c272 100644 --- a/cmd/email.go +++ b/cmd/email.go @@ -17,7 +17,7 @@ var verifyEmailCmd = &cobra.Command{ Aliases: []string{"v"}, Short: "Verify email address", Long: `Performs comprehensive email verification including format validation, MX records check, SMTP verification, and disposable/webmail detection`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runVerifyEmail, } @@ -27,21 +27,19 @@ func init() { } func runVerifyEmail(cmd *cobra.Command, args []string) error { - email := args[0] - c, err := newClient() if err != nil { return err } - response, err := c.VerifyEmail(email) - if err != nil { - return err - } - - if err := checkError(response.Error); err != nil { - return err - } - - return formatter.FormatEmailResults(response, IsJSONOutput()) + return forEachQuery(args, func(email string) error { + response, err := c.VerifyEmail(email) + if err != nil { + return err + } + if err := checkError(response.Error); err != nil { + return err + } + return formatter.FormatEmailResults(response, IsJSONOutput()) + }) } diff --git a/cmd/files.go b/cmd/files.go index aee7d14..6b608ca 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -11,7 +11,7 @@ var filesCmd = &cobra.Command{ Aliases: []string{"f"}, Short: "Search open directory files", Long: `Search for files in open directories using various filters (free OSINT endpoint)`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runFilesSearch, } @@ -30,19 +30,25 @@ func runFilesSearch(cmd *cobra.Command, args []string) error { return err } - params := &models.OpenDirectorySearchParams{ - URL: args[0], - } - params.Filename, _ = cmd.Flags().GetString("filename") - params.Extension, _ = cmd.Flags().GetString("extension") - params.Exclude, _ = cmd.Flags().GetString("exclude") - params.Size, _ = cmd.Flags().GetInt("size") - params.From, _ = cmd.Flags().GetInt("from") - - response, err := c.SearchOpenDirectoryFiles(params) - if err != nil { - return err - } + filename, _ := cmd.Flags().GetString("filename") + extension, _ := cmd.Flags().GetString("extension") + exclude, _ := cmd.Flags().GetString("exclude") + size, _ := cmd.Flags().GetInt("size") + from, _ := cmd.Flags().GetInt("from") - return formatter.FormatFilesResults(*response, IsJSONOutput()) + return forEachQuery(args, func(url string) error { + params := &models.OpenDirectorySearchParams{ + URL: url, + Filename: filename, + Extension: extension, + Exclude: exclude, + Size: size, + From: from, + } + response, err := c.SearchOpenDirectoryFiles(params) + if err != nil { + return err + } + return formatter.FormatFilesResults(*response, IsJSONOutput()) + }) } diff --git a/cmd/moon.go b/cmd/moon.go index 931f64c..f749435 100644 --- a/cmd/moon.go +++ b/cmd/moon.go @@ -13,7 +13,7 @@ var moonCmd = &cobra.Command{ Aliases: []string{"mn"}, Short: "Search moon logs", Long: `Search moon logs with various filters. Requires admin API key.`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runMoon, } @@ -36,40 +36,46 @@ func runMoon(cmd *cobra.Command, args []string) error { return err } - params := &models.MoonParams{ - Query: args[0], - } - params.Filename, _ = cmd.Flags().GetString("filename") - params.MaxHits, _ = cmd.Flags().GetInt("max_hits") + filename, _ := cmd.Flags().GetString("filename") + maxHits, _ := cmd.Flags().GetInt("max_hits") sortBy, _ := cmd.Flags().GetString("sort_by") if sortBy != "" && sortBy != "ingest_timestamp" && sortBy != "date_posted" { return fmt.Errorf("invalid sort_by value: must be 'ingest_timestamp' or 'date_posted'") } - params.SortBy = sortBy - params.IngestStartDate, _ = cmd.Flags().GetString("ingest_start_date") - params.IngestEndDate, _ = cmd.Flags().GetString("ingest_end_date") - params.PostedStartDate, _ = cmd.Flags().GetString("posted_start_date") - params.PostedEndDate, _ = cmd.Flags().GetString("posted_end_date") - params.Format, _ = cmd.Flags().GetString("format") + ingestStart, _ := cmd.Flags().GetString("ingest_start_date") + ingestEnd, _ := cmd.Flags().GetString("ingest_end_date") + postedStart, _ := cmd.Flags().GetString("posted_start_date") + postedEnd, _ := cmd.Flags().GetString("posted_end_date") + format, _ := cmd.Flags().GetString("format") - response, err := c.SearchMoonLogs(params) - if err != nil { - return err - } - - if err := checkError(response.Error); err != nil { - return err - } - - if params.Format != "json" { - fmt.Println(response.Message) + return forEachQuery(args, func(query string) error { + params := &models.MoonParams{ + Query: query, + Filename: filename, + MaxHits: maxHits, + SortBy: sortBy, + IngestStartDate: ingestStart, + IngestEndDate: ingestEnd, + PostedStartDate: postedStart, + PostedEndDate: postedEnd, + Format: format, + } + response, err := c.SearchMoonLogs(params) + if err != nil { + return err + } + if err := checkError(response.Error); err != nil { + return err + } + if params.Format != "json" { + fmt.Println(response.Message) + return nil + } + output, err := formatter.FormatMoonResults(response, IsJSONOutput()) + if err != nil { + return err + } + printOutput(output) return nil - } - - output, err := formatter.FormatMoonResults(response, IsJSONOutput()) - if err != nil { - return err - } - printOutput(output) - return nil + }) } diff --git a/cmd/root.go b/cmd/root.go index 292e96d..a5d407f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -23,6 +23,8 @@ DB.org.ai CLI client`, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return utils.CheckForUpdates(cmd) }, + SilenceUsage: true, + SilenceErrors: true, } func Execute() { @@ -3,6 +3,7 @@ package cmd import ( "fmt" + "git.db.org.ai/dborg/internal/client" "git.db.org.ai/dborg/internal/formatter" "git.db.org.ai/dborg/internal/models" "github.com/spf13/cobra" @@ -11,8 +12,8 @@ import ( var slCmd = &cobra.Command{ Use: "sl [query]", Short: "Search stealer logs", - Long: `Search stealer logs with various filters`, - Args: cobra.ExactArgs(1), + Long: `Search stealer logs with various filters. Accepts a query arg or newline-delimited queries on stdin.`, + Args: argsOrStdin(1), RunE: runSLSearch, } @@ -34,8 +35,14 @@ func runSLSearch(cmd *cobra.Command, args []string) error { return err } + return forEachQuery(args, func(query string) error { + return runSLSearchOne(cmd, c, query) + }) +} + +func runSLSearchOne(cmd *cobra.Command, c *client.Client, query string) error { params := &models.SLParams{ - Query: args[0], + Query: query, } params.Filename, _ = cmd.Flags().GetString("filename") params.MaxHits, _ = cmd.Flags().GetInt("max_hits") diff --git a/cmd/stdin.go b/cmd/stdin.go new file mode 100644 index 0000000..e9240db --- /dev/null +++ b/cmd/stdin.go @@ -0,0 +1,98 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strings" + + "git.db.org.ai/dborg/internal/utils" + "github.com/spf13/cobra" +) + +func stdinPiped() bool { + fi, err := os.Stdin.Stat() + if err != nil { + return false + } + return (fi.Mode() & os.ModeCharDevice) == 0 +} + +func readStdinLines() ([]string, error) { + var lines []string + scanner := bufio.NewScanner(os.Stdin) + scanner.Buffer(make([]byte, 64*1024), 1024*1024) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + lines = append(lines, line) + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("failed to read stdin: %w", err) + } + return lines, nil +} + +func argsOrStdin(n int) cobra.PositionalArgs { + return func(cmd *cobra.Command, args []string) error { + if len(args) == n { + return nil + } + if len(args) == 0 && stdinPiped() { + return nil + } + return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) + } +} + +func resolveQueries(args []string) ([]string, error) { + if len(args) > 0 { + return args, nil + } + if !stdinPiped() { + return nil, fmt.Errorf("no query provided") + } + lines, err := readStdinLines() + if err != nil { + return nil, err + } + if len(lines) == 0 { + return nil, fmt.Errorf("no queries read from stdin") + } + return lines, nil +} + +func forEachQuery(args []string, fn func(query string) error) error { + queries, err := resolveQueries(args) + if err != nil { + return err + } + + multi := len(queries) > 1 + var firstErr error + for i, q := range queries { + if multi { + printQuerySeparator(i, q) + } + if err := fn(q); err != nil { + fmt.Fprintf(os.Stderr, "Error for %q: %v\n", q, err) + if firstErr == nil { + firstErr = err + } + } + } + return firstErr +} + +func printQuerySeparator(i int, q string) { + if utils.IsTerminal() { + if i > 0 { + fmt.Println() + } + fmt.Printf("\033[1;36m━━━ %s ━━━\033[0m\n", q) + } else { + fmt.Printf("--- %s ---\n", q) + } +} diff --git a/cmd/telegram.go b/cmd/telegram.go index 98092a6..23da10a 100644 --- a/cmd/telegram.go +++ b/cmd/telegram.go @@ -17,7 +17,7 @@ var phoneCmd = &cobra.Command{ Aliases: []string{"p"}, Short: "Get phone number for Telegram user", Long: `Retrieves the phone number associated with a Telegram username (with @ prefix) or user ID`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runTelegramPhone, } @@ -27,21 +27,19 @@ func init() { } func runTelegramPhone(cmd *cobra.Command, args []string) error { - identifier := args[0] - c, err := newClient() if err != nil { return err } - response, err := c.GetTelegramPhone(identifier) - if err != nil { - return err - } - - if err := checkError(response.Error); err != nil { - return err - } - - return formatter.FormatTelegramResults(response, IsJSONOutput()) + return forEachQuery(args, func(identifier string) error { + response, err := c.GetTelegramPhone(identifier) + if err != nil { + return err + } + if err := checkError(response.Error); err != nil { + return err + } + return formatter.FormatTelegramResults(response, IsJSONOutput()) + }) } diff --git a/cmd/username.go b/cmd/username.go index ed51d2e..60da503 100644 --- a/cmd/username.go +++ b/cmd/username.go @@ -14,7 +14,7 @@ var usernameCmd = &cobra.Command{ Aliases: []string{"un"}, Short: "Check username availability across websites", Long: `Check username availability across hundreds of websites using WhatsMyName dataset`, - Args: cobra.ExactArgs(1), + Args: argsOrStdin(1), RunE: runUsernameCheck, } @@ -31,30 +31,27 @@ func runUsernameCheck(cmd *cobra.Command, args []string) error { return err } - params := &models.USRSXParams{ - Username: args[0], - } - params.Sites, _ = cmd.Flags().GetStringSlice("sites") - params.Fuzzy, _ = cmd.Flags().GetBool("fuzzy") - params.MaxTasks, _ = cmd.Flags().GetInt("max_tasks") - - err = c.CheckUsernameStream(params, func(result json.RawMessage) error { - if IsJSONOutput() { - fmt.Println(string(result)) - return nil - } + sites, _ := cmd.Flags().GetStringSlice("sites") + fuzzy, _ := cmd.Flags().GetBool("fuzzy") + maxTasks, _ := cmd.Flags().GetInt("max_tasks") - var siteResult models.SiteResult - if err := json.Unmarshal(result, &siteResult); err != nil { - return err + return forEachQuery(args, func(username string) error { + params := &models.USRSXParams{ + Username: username, + Sites: sites, + Fuzzy: fuzzy, + MaxTasks: maxTasks, } - - return formatter.FormatUsernameSiteResult(&siteResult) + return c.CheckUsernameStream(params, func(result json.RawMessage) error { + if IsJSONOutput() { + fmt.Println(string(result)) + return nil + } + var siteResult models.SiteResult + if err := json.Unmarshal(result, &siteResult); err != nil { + return err + } + return formatter.FormatUsernameSiteResult(&siteResult) + }) }) - - if err != nil { - return err - } - - return nil } |
