diff options
| author | s <[email protected]> | 2025-11-25 09:58:42 -0500 |
|---|---|---|
| committer | s <[email protected]> | 2025-11-25 09:58:42 -0500 |
| commit | 8a342848809a26e7e13933180b4df91d4a52f898 (patch) | |
| tree | 6d273e54d6ffb6ae694e21ce587e28348b01aea5 | |
| parent | 8472267b60b204cea5fbdeaf8fe06443822d1bfb (diff) | |
| download | dborg-1.0.6.tar.gz dborg-1.0.6.zip | |
feat: add dns site check, services list, and additional twitter/x api endpointsv1.0.6
| -rw-r--r-- | cmd/dns.go | 35 | ||||
| -rw-r--r-- | cmd/services.go | 49 | ||||
| -rw-r--r-- | cmd/x.go | 198 | ||||
| -rw-r--r-- | internal/client/client.go | 4 | ||||
| -rw-r--r-- | internal/client/dns.go | 15 | ||||
| -rw-r--r-- | internal/client/x.go | 90 | ||||
| -rw-r--r-- | internal/formatter/admin.go | 1 | ||||
| -rw-r--r-- | internal/formatter/dns.go | 35 | ||||
| -rw-r--r-- | internal/formatter/x.go | 43 | ||||
| -rw-r--r-- | internal/models/dns.go | 7 |
10 files changed, 477 insertions, 0 deletions
@@ -23,6 +23,14 @@ var dnsTLDCmd = &cobra.Command{ RunE: runDNSTLDCheck, } +var dnsSiteCmd = &cobra.Command{ + Use: "site [url]", + 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), + RunE: runDNSSiteCheck, +} + func runDNSTLDCheck(cmd *cobra.Command, args []string) error { term := args[0] showOnly, _ := cmd.Flags().GetString("show-only") @@ -60,9 +68,36 @@ func runDNSTLDCheck(cmd *cobra.Command, args []string) error { 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 +} + func init() { rootCmd.AddCommand(dnsCmd) dnsCmd.AddCommand(dnsTLDCmd) + dnsCmd.AddCommand(dnsSiteCmd) dnsTLDCmd.Flags().StringP("show-only", "s", "", "Filter results: 'exists' (only existing domains), 'nxdomain' (only non-existing domains), or empty (show all)") } diff --git a/cmd/services.go b/cmd/services.go new file mode 100644 index 0000000..56c2149 --- /dev/null +++ b/cmd/services.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "encoding/json" + "fmt" + + "github.com/spf13/cobra" +) + +var servicesCmd = &cobra.Command{ + Use: "services", + Short: "List all available services and pricing", + Long: `Get a list of all available services and their credit costs`, + RunE: runServices, +} + +func init() { + rootCmd.AddCommand(servicesCmd) +} + +func runServices(cmd *cobra.Command, args []string) error { + c, err := newUnauthenticatedClient() + if err != nil { + return err + } + + data, err := c.ListServices() + if err != nil { + return err + } + + if IsJSONOutput() { + fmt.Println(string(data)) + return nil + } + + var services map[string]interface{} + if err := json.Unmarshal(data, &services); err != nil { + return fmt.Errorf("failed to parse services: %w", err) + } + + fmt.Println("\nAvailable Services:") + fmt.Println("===================\n") + + servicesData, _ := json.MarshalIndent(services, "", " ") + fmt.Println(string(servicesData)) + + return nil +} @@ -70,6 +70,12 @@ func init() { xCmd.AddCommand(xNFLCmd) xCmd.AddCommand(xRepliesCmd) xCmd.AddCommand(xSearchCmd) + xCmd.AddCommand(xDeletedTweetsCmd) + xCmd.AddCommand(xDomainCmd) + xCmd.AddCommand(xHoldersMapCmd) + xCmd.AddCommand(xIDCmd) + xCmd.AddCommand(xImageCmd) + xCmd.AddCommand(xUserIDCmd) xRepliesCmd.Flags().Int("limit", 100, "Maximum number of replies to fetch") xSearchCmd.Flags().Int("limit", 100, "Maximum number of tweets to fetch") @@ -225,3 +231,195 @@ func runXSearch(cmd *cobra.Command, args []string) error { return nil } + +var xDeletedTweetsCmd = &cobra.Command{ + Use: "deleted-tweets [handle]", + Short: "Check deleted tweets for a Twitter/X account", + Long: `Checks deleted token-related tweets from a Twitter account`, + Args: cobra.ExactArgs(1), + RunE: runXDeletedTweets, +} + +var xDomainCmd = &cobra.Command{ + Use: "domain [domain]", + Short: "Check domain/website age", + Long: `Checks the age of a domain/website`, + Args: cobra.ExactArgs(1), + RunE: runXDomain, +} + +var xHoldersMapCmd = &cobra.Command{ + Use: "holders-map [address]", + Short: "Analyze holder trading behavior for a token", + Long: `Analyzes trading behavior of top 50 holders for a token`, + Args: cobra.ExactArgs(1), + RunE: runXHoldersMap, +} + +var xIDCmd = &cobra.Command{ + Use: "id [handle]", + Short: "Get Twitter ID for a handle", + Long: `Retrieves the Twitter ID for a given handle`, + Args: cobra.ExactArgs(1), + RunE: runXID, +} + +var xImageCmd = &cobra.Command{ + Use: "image [address]", + Short: "Reverse image search for a token", + Long: `Performs reverse image search for a token (SOL/TRON)`, + Args: cobra.ExactArgs(1), + RunE: runXImage, +} + +var xUserIDCmd = &cobra.Command{ + Use: "user-id [handle]", + Short: "Get Twitter user ID for a handle", + Long: `Retrieves the Twitter user ID for a given handle`, + Args: cobra.ExactArgs(1), + RunE: runXUserID, +} + +func runXDeletedTweets(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.CheckDeletedTweets(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} + +func runXDomain(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.CheckDomainAge(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} + +func runXHoldersMap(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.GetHoldersMap(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} + +func runXID(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.GetTwitterID(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} + +func runXImage(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.ReverseImageSearch(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} + +func runXUserID(cmd *cobra.Command, args []string) error { + c, err := newClient() + if err != nil { + return err + } + + response, err := c.GetTwitterUserID(args[0]) + if err != nil { + return err + } + + if err := checkError(response.Error); err != nil { + return err + } + + output, err := formatter.FormatXGeneric(response, IsJSONOutput()) + if err != nil { + return err + } + + printOutput(output) + return nil +} diff --git a/internal/client/client.go b/internal/client/client.go index eaf87cb..4aa6f06 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -126,3 +126,7 @@ func (c *Client) Patch(path string, body interface{}) ([]byte, error) { func (c *Client) Put(path string, body interface{}) ([]byte, error) { return c.doRequest(http.MethodPut, path, nil, body) } + +func (c *Client) ListServices() ([]byte, error) { + return c.Get("/", nil) +} diff --git a/internal/client/dns.go b/internal/client/dns.go index 9f9d4e8..96ae8e1 100644 --- a/internal/client/dns.go +++ b/internal/client/dns.go @@ -59,3 +59,18 @@ func (c *Client) CheckDNSTLDStream(params *models.DNSTLDParams, callback func(re return nil } + +func (c *Client) CheckDNSSite(siteURL string) (*models.DNSResponse, error) { + path := fmt.Sprintf("/dns/site/%s", url.PathEscape(siteURL)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.DNSResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse DNS site response: %w", err) + } + + return &response, nil +} diff --git a/internal/client/x.go b/internal/client/x.go index b6ddba8..f385b9b 100644 --- a/internal/client/x.go +++ b/internal/client/x.go @@ -207,3 +207,93 @@ func (c *Client) SearchTweetsStream(query string, limit int, callback func(resul return nil } + +func (c *Client) CheckDeletedTweets(handle string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/deleted-tweets/%s", url.PathEscape(handle)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse deleted tweets response: %w", err) + } + + return &response, nil +} + +func (c *Client) CheckDomainAge(domain string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/domain/%s", url.PathEscape(domain)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse domain age response: %w", err) + } + + return &response, nil +} + +func (c *Client) GetHoldersMap(address string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/holders/map/%s", url.PathEscape(address)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse holders map response: %w", err) + } + + return &response, nil +} + +func (c *Client) GetTwitterID(handle string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/id/%s", url.PathEscape(handle)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse Twitter ID response: %w", err) + } + + return &response, nil +} + +func (c *Client) ReverseImageSearch(address string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/image/%s", url.PathEscape(address)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse image search response: %w", err) + } + + return &response, nil +} + +func (c *Client) GetTwitterUserID(handle string) (*models.XResponse, error) { + path := fmt.Sprintf("/x/user-id/%s", url.PathEscape(handle)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.XResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse Twitter user ID response: %w", err) + } + + return &response, nil +} diff --git a/internal/formatter/admin.go b/internal/formatter/admin.go index 914eaaa..12ffcd0 100644 --- a/internal/formatter/admin.go +++ b/internal/formatter/admin.go @@ -185,3 +185,4 @@ func FormatAccountToggled(message string, asJSON bool) (string, error) { return fmt.Sprintf("%s %s\n", Blue("ℹ"), message), nil } + diff --git a/internal/formatter/dns.go b/internal/formatter/dns.go index 6abd5b0..8e66039 100644 --- a/internal/formatter/dns.go +++ b/internal/formatter/dns.go @@ -1,6 +1,7 @@ package formatter import ( + "bytes" "encoding/json" "fmt" "strings" @@ -55,3 +56,37 @@ func FormatDNSResults(result *models.DomainResult, asJSON bool) (string, error) return sb.String(), nil } + +func FormatDNSSite(resp *models.DNSResponse, asJSON bool) (string, error) { + if asJSON { + data, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return "", fmt.Errorf("failed to marshal JSON: %w", err) + } + return string(data), nil + } + + var buf bytes.Buffer + + if resp.Error != "" { + fmt.Fprintf(&buf, "%s\n", Red(fmt.Sprintf("Error: %s", resp.Error))) + return buf.String(), nil + } + + if resp.Message != "" { + fmt.Fprintf(&buf, "%s\n", Bold(Cyan(resp.Message))) + } + + if resp.Response != "" { + fmt.Fprintf(&buf, "%s\n", resp.Response) + } + + if resp.Data != nil && len(resp.Data) > 0 { + dataJSON, err := json.MarshalIndent(resp.Data, "", " ") + if err == nil { + fmt.Fprintf(&buf, "\n%s\n", string(dataJSON)) + } + } + + return buf.String(), nil +} diff --git a/internal/formatter/x.go b/internal/formatter/x.go index f701797..a79d173 100644 --- a/internal/formatter/x.go +++ b/internal/formatter/x.go @@ -377,3 +377,46 @@ func wrapText(text string, width int) []string { return lines } + +func FormatXGeneric(resp *models.XResponse, asJSON bool) (string, error) { + if asJSON { + data, err := json.MarshalIndent(resp, "", " ") + if err != nil { + return "", fmt.Errorf("failed to marshal JSON: %w", err) + } + return string(data), nil + } + + var buf bytes.Buffer + + if resp.Error != "" { + fmt.Fprintf(&buf, "%s\n", Red(fmt.Sprintf("Error: %s", resp.Error))) + return buf.String(), nil + } + + if resp.Message != "" { + fmt.Fprintf(&buf, "%s\n\n", Bold(Cyan(resp.Message))) + } + + if resp.Response != "" { + fmt.Fprintf(&buf, "%s\n\n", resp.Response) + } + + if resp.Data != nil { + dataJSON, err := json.MarshalIndent(resp.Data, "", " ") + if err == nil { + fmt.Fprintf(&buf, "%s\n", string(dataJSON)) + } + } + + if resp.Credits.Remaining > 0 || resp.Credits.Unlimited { + fmt.Fprintf(&buf, "\n%s ", Blue("Credits Remaining:")) + if resp.Credits.Unlimited { + fmt.Fprintf(&buf, "%s\n", Green("Unlimited")) + } else { + fmt.Fprintf(&buf, "%s\n", FormatCredits(int64(resp.Credits.Remaining))) + } + } + + return buf.String(), nil +} diff --git a/internal/models/dns.go b/internal/models/dns.go index 51d9e50..776e3d6 100644 --- a/internal/models/dns.go +++ b/internal/models/dns.go @@ -11,3 +11,10 @@ type DomainResult struct { Title string `json:"title,omitempty"` Tech []string `json:"tech,omitempty"` } + +type DNSResponse struct { + Message string `json:"message,omitempty"` + Data map[string]interface{} `json:"data,omitempty"` + Error string `json:"error,omitempty"` + Response string `json:"response,omitempty"` +} |
