diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/client/client.go | 9 | ||||
| -rw-r--r-- | internal/client/client_test.go | 42 | ||||
| -rw-r--r-- | internal/client/osint.go | 33 | ||||
| -rw-r--r-- | internal/client/x.go | 30 | ||||
| -rw-r--r-- | internal/models/osint.go | 11 | ||||
| -rw-r--r-- | internal/models/x.go | 30 |
6 files changed, 155 insertions, 0 deletions
diff --git a/internal/client/client.go b/internal/client/client.go index 468fae9..eaf87cb 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -29,6 +29,15 @@ func New(cfg *config.Config) (*Client, error) { }, nil } +func NewUnauthenticated(cfg *config.Config) (*Client, error) { + return &Client{ + config: cfg, + httpClient: &http.Client{ + Timeout: cfg.Timeout, + }, + }, nil +} + func (c *Client) doRequest(method, path string, params url.Values, body interface{}) ([]byte, error) { fullURL := c.config.BaseURL + path if params != nil && len(params) > 0 { diff --git a/internal/client/client_test.go b/internal/client/client_test.go index 31939fb..fb21755 100644 --- a/internal/client/client_test.go +++ b/internal/client/client_test.go @@ -44,3 +44,45 @@ func TestNewClient(t *testing.T) { }) } } + +func TestNewUnauthenticatedClient(t *testing.T) { + tests := []struct { + name string + config *config.Config + wantErr bool + }{ + { + name: "config with API key", + config: &config.Config{ + APIKey: "test-key", + BaseURL: "https://db.org.ai", + Timeout: 30 * time.Second, + MaxRetries: 3, + UserAgent: "test-agent", + }, + wantErr: false, + }, + { + name: "config without API key", + config: &config.Config{ + BaseURL: "https://db.org.ai", + Timeout: 30 * time.Second, + MaxRetries: 3, + UserAgent: "test-agent", + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := NewUnauthenticated(tt.config) + if (err != nil) != tt.wantErr { + t.Errorf("NewUnauthenticated() error = %v, wantErr %v", err, tt.wantErr) + } + if c == nil && !tt.wantErr { + t.Error("NewUnauthenticated() returned nil client") + } + }) + } +} diff --git a/internal/client/osint.go b/internal/client/osint.go index 20f53ce..95e3550 100644 --- a/internal/client/osint.go +++ b/internal/client/osint.go @@ -55,3 +55,36 @@ func (c *Client) SearchBreachForum(params *models.BreachForumSearchParams) (*mod return &response, nil } + +func (c *Client) SearchOpenDirectoryFiles(params *models.OpenDirectorySearchParams) (*models.OpenDirectorySearchResponse, error) { + path := fmt.Sprintf("/osint/files/%s", url.PathEscape(params.URL)) + + queryParams := url.Values{} + if params.Filename != "" { + queryParams.Add("filename", params.Filename) + } + if params.Extension != "" { + queryParams.Add("extension", params.Extension) + } + if params.Exclude != "" { + queryParams.Add("exclude", params.Exclude) + } + if params.Size > 0 { + queryParams.Add("size", fmt.Sprintf("%d", params.Size)) + } + if params.From > 0 { + queryParams.Add("from", fmt.Sprintf("%d", params.From)) + } + + data, err := c.Get(path, queryParams) + if err != nil { + return nil, err + } + + var response models.OpenDirectorySearchResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse open directory search response: %w", err) + } + + return &response, nil +} diff --git a/internal/client/x.go b/internal/client/x.go index 6c899ad..bd16692 100644 --- a/internal/client/x.go +++ b/internal/client/x.go @@ -26,6 +26,36 @@ func (c *Client) SearchTwitterHistory(username string) (*models.XResponse, error return &response, nil } +func (c *Client) GetFirstFollowers(username string) (*models.FirstFollowersResponse, error) { + path := fmt.Sprintf("/x/first/%s", url.PathEscape(username)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.FirstFollowersResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse first followers response: %w", err) + } + + return &response, nil +} + +func (c *Client) GetNotableFollowers(username string) (*models.NotableFollowersResponse, error) { + path := fmt.Sprintf("/x/nfl/%s", url.PathEscape(username)) + data, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var response models.NotableFollowersResponse + if err := json.Unmarshal(data, &response); err != nil { + return nil, fmt.Errorf("failed to parse notable followers response: %w", err) + } + + return &response, nil +} + func (c *Client) FetchTweetsStream(username string, callback func(result json.RawMessage) error) error { path := fmt.Sprintf("/x/tweets/%s", url.PathEscape(username)) fullURL := c.config.BaseURL + path diff --git a/internal/models/osint.go b/internal/models/osint.go index 6096df8..9f714c4 100644 --- a/internal/models/osint.go +++ b/internal/models/osint.go @@ -36,3 +36,14 @@ type BreachForumSearchResponse struct { MaxHits int `json:"max_hits"` Results interface{} `json:"results"` } + +type OpenDirectorySearchParams struct { + URL string + Filename string + Extension string + Exclude string + Size int + From int +} + +type OpenDirectorySearchResponse map[string]interface{} diff --git a/internal/models/x.go b/internal/models/x.go index b4e6eac..07c3117 100644 --- a/internal/models/x.go +++ b/internal/models/x.go @@ -49,3 +49,33 @@ type TweetsStreamResponse struct { Complete *Complete `json:"complete,omitempty"` Error string `json:"error,omitempty"` } + +type FirstFollower struct { + Number int `json:"number"` + Username string `json:"username"` + Name string `json:"name"` +} + +type FirstFollowersResponse struct { + Username string `json:"username"` + Followers []FirstFollower `json:"followers"` + Credits struct { + Remaining int `json:"remaining"` + Unlimited bool `json:"unlimited"` + } `json:"credits"` +} + +type NotableFollower struct { + Username string `json:"username"` + FollowerCount string `json:"follower_count"` + Score float64 `json:"score"` +} + +type NotableFollowersResponse struct { + Username string `json:"username"` + Followers []NotableFollower `json:"followers"` + Credits struct { + Remaining int `json:"remaining"` + Unlimited bool `json:"unlimited"` + } `json:"credits"` +} |
