diff options
| author | s <[email protected]> | 2025-12-20 02:45:32 -0500 |
|---|---|---|
| committer | s <[email protected]> | 2025-12-20 02:45:32 -0500 |
| commit | bfd971bbc8d35685f18f4b9dd3a52f04f8b4f77f (patch) | |
| tree | 2003679a51efaa7c1a43fe4f6da95530de8ce8aa | |
| parent | c8ad5b9ef9fdc094c2cd974d6b9a65112089922b (diff) | |
| download | dborg-bfd971bbc8d35685f18f4b9dd3a52f04f8b4f77f.tar.gz dborg-bfd971bbc8d35685f18f4b9dd3a52f04f8b4f77f.zip | |
feat: add moon logs search command and filename filter support for stealer logsv1.0.9
| -rw-r--r-- | cmd/me.go | 41 | ||||
| -rw-r--r-- | cmd/moon.go | 74 | ||||
| -rw-r--r-- | cmd/sl.go | 2 | ||||
| -rw-r--r-- | internal/client/moon.go | 57 | ||||
| -rw-r--r-- | internal/client/sl.go | 3 | ||||
| -rw-r--r-- | internal/formatter/moon.go | 85 | ||||
| -rw-r--r-- | internal/models/moon.go | 20 | ||||
| -rw-r--r-- | internal/models/sl.go | 1 |
8 files changed, 283 insertions, 0 deletions
diff --git a/cmd/me.go b/cmd/me.go new file mode 100644 index 0000000..e5ba7ec --- /dev/null +++ b/cmd/me.go @@ -0,0 +1,41 @@ +package cmd + +import ( + "git.db.org.ai/dborg/internal/formatter" + "github.com/spf13/cobra" +) + +var meCmd = &cobra.Command{ + Use: "me", + Short: "Get account information and usage statistics", + Long: `Get your account information, credits, and usage statistics.`, + RunE: runMe, +} + +func init() { + rootCmd.AddCommand(meCmd) +} + +func runMe(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.GetAccountStats() + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatAccountStats(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} diff --git a/cmd/moon.go b/cmd/moon.go new file mode 100644 index 0000000..512fb7e --- /dev/null +++ b/cmd/moon.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "fmt" + + "git.db.org.ai/dborg/internal/formatter" + "git.db.org.ai/dborg/internal/models" + "github.com/spf13/cobra" +) + +var moonCmd = &cobra.Command{ + Use: "moon [query]", + Short: "Search moon logs", + Long: `Search moon logs with various filters. Requires admin API key.`, + Args: cobra.ExactArgs(1), + RunE: runMoon, +} + +func init() { + rootCmd.AddCommand(moonCmd) + + moonCmd.Flags().StringP("filename", "F", "", "Filter by filename") + moonCmd.Flags().IntP("max_hits", "n", 10, "Maximum number of hits to return") + moonCmd.Flags().StringP("sort_by", "s", "", "Sort by field (ingest_timestamp or date_posted)") + moonCmd.Flags().StringP("ingest_start_date", "i", "", "Ingest timestamp start date") + moonCmd.Flags().StringP("ingest_end_date", "e", "", "Ingest timestamp end date") + moonCmd.Flags().StringP("posted_start_date", "p", "", "Date posted start date") + moonCmd.Flags().StringP("posted_end_date", "D", "", "Date posted end date") + moonCmd.Flags().StringP("format", "f", "json", "Response format (json or custom like 'ulp', 'up', 'pul')") +} + +func runMoon(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + params := &models.MoonParams{ + Query: args[0], + } + params.Filename, _ = cmd.Flags().GetString("filename") + params.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") + + 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 +} @@ -18,6 +18,7 @@ var slCmd = &cobra.Command{ func init() { rootCmd.AddCommand(slCmd) + slCmd.Flags().StringP("filename", "F", "", "Filter by filename") slCmd.Flags().IntP("max_hits", "n", 10, "Maximum number of hits to return") slCmd.Flags().StringP("sort_by", "s", "", "Sort by field (ingest_timestamp or date_posted)") slCmd.Flags().StringP("ingest_start_date", "i", "", "Ingest timestamp start date") @@ -36,6 +37,7 @@ func runSLSearch(cmd *cobra.Command, args []string) error { params := &models.SLParams{ Query: args[0], } + params.Filename, _ = cmd.Flags().GetString("filename") params.MaxHits, _ = cmd.Flags().GetInt("max_hits") sortBy, _ := cmd.Flags().GetString("sort_by") if sortBy != "" && sortBy != "ingest_timestamp" && sortBy != "date_posted" { diff --git a/internal/client/moon.go b/internal/client/moon.go new file mode 100644 index 0000000..daef57e --- /dev/null +++ b/internal/client/moon.go @@ -0,0 +1,57 @@ +package client + +import ( + "encoding/json" + "fmt" + "net/url" + + "git.db.org.ai/dborg/internal/models" +) + +func (c *Client) SearchMoonLogs(params *models.MoonParams) (*models.MoonResponse, error) { + queryParams := url.Values{} + queryParams.Add("query", params.Query) + + if params.Filename != "" { + queryParams.Add("filename", params.Filename) + } + if params.MaxHits > 0 && params.MaxHits != 10 { + queryParams.Add("max_hits", fmt.Sprintf("%d", params.MaxHits)) + } + if params.SortBy != "" { + queryParams.Add("sort_by", params.SortBy) + } + if params.IngestStartDate != "" { + queryParams.Add("ingest_start_date", params.IngestStartDate) + } + if params.IngestEndDate != "" { + queryParams.Add("ingest_end_date", params.IngestEndDate) + } + if params.PostedStartDate != "" { + queryParams.Add("posted_start_date", params.PostedStartDate) + } + if params.PostedEndDate != "" { + queryParams.Add("posted_end_date", params.PostedEndDate) + } + if params.Format != "" && params.Format != "json" { + queryParams.Add("format", params.Format) + } + + data, err := c.Get("/moon/search", queryParams) + if err != nil { + return nil, err + } + + if params.Format != "" && params.Format != "json" { + return &models.MoonResponse{ + Message: string(data), + }, nil + } + + var response models.MoonResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse moon logs response: %w", err) + } + + return &response, nil +} diff --git a/internal/client/sl.go b/internal/client/sl.go index c8754cf..e67bee1 100644 --- a/internal/client/sl.go +++ b/internal/client/sl.go @@ -11,6 +11,9 @@ func (c *Client) SearchStealerLogs(params *models.SLParams) (*models.SLResponse, queryParams := url.Values{} queryParams.Add("query", params.Query) + if params.Filename != "" { + queryParams.Add("filename", params.Filename) + } if params.MaxHits > 0 && params.MaxHits != 10 { queryParams.Add("max_hits", fmt.Sprintf("%d", params.MaxHits)) } diff --git a/internal/formatter/moon.go b/internal/formatter/moon.go new file mode 100644 index 0000000..e3930c7 --- /dev/null +++ b/internal/formatter/moon.go @@ -0,0 +1,85 @@ +package formatter + +import ( + "encoding/json" + "fmt" + "strings" + + "git.db.org.ai/dborg/internal/models" +) + +func FormatMoonResults(resp *models.MoonResponse, asJSON bool) (string, error) { + if asJSON { + data, err := json.MarshalIndent(resp.Results, "", " ") + if err != nil { + return "", fmt.Errorf("failed to marshal JSON: %w", err) + } + return string(data), nil + } + + var sb strings.Builder + + if resp.Results == nil { + sb.WriteString(fmt.Sprintf("\n%s\n\n", Gray("No results found"))) + return sb.String(), nil + } + + resultsMap, ok := resp.Results.(map[string]interface{}) + if !ok { + resultsJSON, err := json.MarshalIndent(resp.Results, "", " ") + if err != nil { + return "", fmt.Errorf("failed to format results: %w", err) + } + return string(resultsJSON), nil + } + + hits, ok := resultsMap["hits"].([]interface{}) + if !ok || len(hits) == 0 { + sb.WriteString(fmt.Sprintf("\n%s\n\n", Gray("No results found"))) + return sb.String(), nil + } + + numHits, _ := resultsMap["num_hits"].(float64) + elapsed, _ := resultsMap["elapsed_time_micros"].(float64) + + sb.WriteString(fmt.Sprintf("%s %s %s\n", + Cyan("Found"), + Bold(Yellow(fmt.Sprintf("%d", int(numHits)))), + Cyan(fmt.Sprintf("moon log entries (%.2fms)", elapsed/1000)))) + sb.WriteString("\n") + + for i, hit := range hits { + hitMap, ok := hit.(map[string]interface{}) + if !ok { + continue + } + + if i > 0 { + sb.WriteString(Dim("───")) + sb.WriteString("\n") + } + + username, _ := hitMap["username"].(string) + password, _ := hitMap["password"].(string) + url, _ := hitMap["url"].(string) + filename, _ := hitMap["filename"].(string) + + sb.WriteString(fmt.Sprintf("%s %s\n", Dim("Username:"), Bold(username))) + + if password != "" { + sb.WriteString(fmt.Sprintf("%s %s\n", Dim("Password:"), Yellow(password))) + } + + if url != "" { + sb.WriteString(fmt.Sprintf("%s %s\n", Dim("URL:"), Blue(url))) + } + + if filename != "" { + sb.WriteString(fmt.Sprintf("%s %s\n", Dim("Source:"), Magenta(filename))) + } + + sb.WriteString("\n") + } + + return sb.String(), nil +} diff --git a/internal/models/moon.go b/internal/models/moon.go new file mode 100644 index 0000000..bedfc1c --- /dev/null +++ b/internal/models/moon.go @@ -0,0 +1,20 @@ +package models + +type MoonParams struct { + Query string `json:"query"` + Filename string `json:"filename,omitempty"` + MaxHits int `json:"max_hits,omitempty"` + SortBy string `json:"sort_by,omitempty"` + IngestStartDate string `json:"ingest_start_date,omitempty"` + IngestEndDate string `json:"ingest_end_date,omitempty"` + PostedStartDate string `json:"posted_start_date,omitempty"` + PostedEndDate string `json:"posted_end_date,omitempty"` + Format string `json:"format,omitempty"` +} + +type MoonResponse struct { + MaxHits int `json:"max_hits"` + Results interface{} `json:"results"` + Message string `json:"message,omitempty"` + Error string `json:"error,omitempty"` +} diff --git a/internal/models/sl.go b/internal/models/sl.go index d55279f..f520450 100644 --- a/internal/models/sl.go +++ b/internal/models/sl.go @@ -2,6 +2,7 @@ package models type SLParams struct { Query string `json:"query"` + Filename string `json:"filename,omitempty"` MaxHits int `json:"max_hits,omitempty"` SortBy string `json:"sort_by,omitempty"` IngestStartDate string `json:"ingest_start_date,omitempty"` |
