summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors <[email protected]>2025-11-25 09:58:42 -0500
committers <[email protected]>2025-11-25 09:58:42 -0500
commit8a342848809a26e7e13933180b4df91d4a52f898 (patch)
tree6d273e54d6ffb6ae694e21ce587e28348b01aea5
parent8472267b60b204cea5fbdeaf8fe06443822d1bfb (diff)
downloaddborg-8a342848809a26e7e13933180b4df91d4a52f898.tar.gz
dborg-8a342848809a26e7e13933180b4df91d4a52f898.zip
feat: add dns site check, services list, and additional twitter/x api endpointsv1.0.6
-rw-r--r--cmd/dns.go35
-rw-r--r--cmd/services.go49
-rw-r--r--cmd/x.go198
-rw-r--r--internal/client/client.go4
-rw-r--r--internal/client/dns.go15
-rw-r--r--internal/client/x.go90
-rw-r--r--internal/formatter/admin.go1
-rw-r--r--internal/formatter/dns.go35
-rw-r--r--internal/formatter/x.go43
-rw-r--r--internal/models/dns.go7
10 files changed, 477 insertions, 0 deletions
diff --git a/cmd/dns.go b/cmd/dns.go
index f5de4f9..30757c9 100644
--- a/cmd/dns.go
+++ b/cmd/dns.go
@@ -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
+}
diff --git a/cmd/x.go b/cmd/x.go
index b2554e4..d8198ac 100644
--- a/cmd/x.go
+++ b/cmd/x.go
@@ -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"`
+}