diff --git a/.gitignore b/.gitignore index 8022ff2..b88196a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ # Credentials .jsmon/credentials -# Configuration -config.go +# Updated config.go jsmon \ No newline at end of file diff --git a/api.go b/api.go index d7dcd6e..4221a5a 100644 --- a/api.go +++ b/api.go @@ -3,6 +3,7 @@ package main import ( "bufio" "bytes" + "context" "encoding/json" "fmt" "io" @@ -15,9 +16,29 @@ import ( "os" "path/filepath" "strings" - // "time" + "time" + + "golang.org/x/time/rate" +) + +const ( + defaultTimeout = 30 * time.Second + maxRetries = 3 + retryDelay = 1 * time.Second +) + +var ( + httpClient *http.Client + limiter *rate.Limiter ) +func init() { + httpClient = &http.Client{ + Timeout: defaultTimeout, + } + limiter = rate.NewLimiter(rate.Every(time.Second), 10) // 10 requests per second +} + type DiffItem struct { Added bool `json:"added"` Removed bool `json:"removed"` @@ -103,44 +124,73 @@ type RescanDomainResponse struct { TotalUrls int `json:"totalUrls"` } +func makeRequest(ctx context.Context, method, url string, body io.Reader, headers map[string]string) (*http.Response, error) { + if err := limiter.Wait(ctx); err != nil { + return nil, fmt.Errorf("rate limit exceeded: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, method, url, body) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + + for key, value := range headers { + req.Header.Set(key, value) + } + + req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + + var resp *http.Response + var attempt int + for attempt = 0; attempt < maxRetries; attempt++ { + resp, err = httpClient.Do(req) + if err == nil { + break + } + time.Sleep(retryDelay) + } + + if err != nil { + return nil, fmt.Errorf("error sending request after %d attempts: %w", maxRetries, err) + } + + return resp, nil +} + func rescanDomain(domain string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/rescanDomain", apiBaseURL) requestBody, err := json.Marshal(map[string]string{ "domain": domain, }) if err != nil { - fmt.Println("Error creating request body:", err) + log.Printf("Error creating request body: %v", err) return } - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(requestBody), headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var result RescanDomainResponse - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -149,35 +199,31 @@ func rescanDomain(domain string) { } func totalAnalysisData() { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/totalCountAnalysisData", apiBaseURL) - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var results AnalysisData - err = json.Unmarshal(body, &results) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &results); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -200,36 +246,33 @@ func totalAnalysisData() { fmt.Printf("Total IP Addresses: %d\n", results.TotalIpAddresses) fmt.Printf("Total GraphQL Queries: %d\n", results.TotalGql) } + func searchUrlsByDomain(domain string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/searchUrlbyDomain?domain=%s", apiBaseURL, url.QueryEscape(domain)) - req, err := http.NewRequest("POST", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var result SearchUrlsByDomainResponse - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -239,10 +282,12 @@ func searchUrlsByDomain(domain string) { for _, entry := range result.URLs { fmt.Printf("- %s\n", entry.URL) } - } func uploadUrlEndpoint(url string, customHeaders []string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/uploadUrl", apiBaseURL) headerObjects := make([]map[string]string, 0) @@ -260,30 +305,24 @@ func uploadUrlEndpoint(url string, customHeaders []string) { "headers": headerObjects, }) if err != nil { - fmt.Println("Error creating request body:", err) + log.Printf("Error creating request body: %v", err) return } - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(requestBody), headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } @@ -295,9 +334,8 @@ func uploadUrlEndpoint(url string, customHeaders []string) { URL string `json:"url"` } - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -314,44 +352,38 @@ func uploadUrlEndpoint(url string, customHeaders []string) { } } -// Function : func rescanUrlEndpoint(scanId string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/rescanURL/%s", apiBaseURL, scanId) - req, err := http.NewRequest("POST", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var result interface{} - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } - // Pretty print JSON prettyJSON, err := json.MarshalIndent(result, "", " ") if err != nil { - fmt.Println("Error formatting JSON:", err) + log.Printf("Error formatting JSON: %v", err) return } @@ -359,45 +391,43 @@ func rescanUrlEndpoint(scanId string) { } func getDomains() { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/getDomains", apiBaseURL) - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var domains []string - err = json.Unmarshal(body, &domains) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &domains); err != nil { + log.Printf("Error parsing JSON: %v", err) return } - // Print each domain on a new line for _, domain := range domains { fmt.Println(domain) } } func createWordList(domains []string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/createWordList", apiBaseURL) requestBody := addWordlistRequest{ @@ -405,31 +435,24 @@ func createWordList(domains []string) { } body, err := json.Marshal(requestBody) if err != nil { - fmt.Printf("failed to marshal request body: %v\n", err) + log.Printf("failed to marshal request body: %v", err) return } - // Create HTTP request - client := &http.Client{} - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(body)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(body), headers) if err != nil { - fmt.Printf("failed to send request: %v\n", err) + log.Printf("failed to send request: %v", err) return } defer resp.Body.Close() responseBody, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("failed to read response body: %v\n", err) + log.Printf("failed to read response body: %v", err) return } @@ -437,41 +460,37 @@ func createWordList(domains []string) { } func scanFileEndpoint(fileId string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/scanFile/%s", apiBaseURL, fileId) - req, err := http.NewRequest("POST", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var result interface{} - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } prettyJSON, err := json.MarshalIndent(result, "", " ") if err != nil { - fmt.Println("Error formatting JSON:", err) + log.Printf("Error formatting JSON: %v", err) return } @@ -479,7 +498,6 @@ func scanFileEndpoint(fileId string) { } func addCustomWordUser(words []string) { - // Remove empty strings from the words slice cleanedWords := []string{} for _, word := range words { if strings.TrimSpace(word) != "" { @@ -487,7 +505,6 @@ func addCustomWordUser(words []string) { } } - // Prompt user for operation: append or overwrite reader := bufio.NewReader(os.Stdin) fmt.Println("Do you want to append or overwrite the custom words?") fmt.Println("1. Append") @@ -507,76 +524,66 @@ func addCustomWordUser(words []string) { return } - // Append the selected operation to the endpoint as a query parameter + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/addCustomWords?operation=%s", apiBaseURL, operation) - // Create request body requestBody := addCustomWordsRequest{ Words: cleanedWords, } body, err := json.Marshal(requestBody) if err != nil { - fmt.Printf("failed to marshal request body: %v\n", err) + log.Printf("failed to marshal request body: %v", err) return } - // Create HTTP request - client := &http.Client{} - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(body)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - // Set headers - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // Send the request - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(body), headers) if err != nil { - fmt.Printf("failed to send request: %v\n", err) + log.Printf("failed to send request: %v", err) return } defer resp.Body.Close() - // Decode and pretty-print the response var response map[string]interface{} - err = json.NewDecoder(resp.Body).Decode(&response) - if err != nil { - fmt.Printf("failed to unmarshal JSON response: %v\n", err) + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { + log.Printf("failed to unmarshal JSON response: %v", err) return } jsonData, err := json.MarshalIndent(response, "", " ") if err != nil { - fmt.Printf("failed to marshal response for pretty print: %v\n", err) + log.Printf("failed to marshal response for pretty print: %v", err) return } fmt.Printf("%s\n", jsonData) } + func urlsmultipleResponse() { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/urlWithMultipleResponse", apiBaseURL) - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return + + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } @@ -585,9 +592,8 @@ func urlsmultipleResponse() { Data []string `json:"data"` } - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &response); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -599,11 +605,12 @@ func urlsmultipleResponse() { } func uploadFileEndpoint(filePath string, headers []string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/uploadFile", apiBaseURL) headerMaps := []map[string]string{} - - // Parse headers into the correct format for _, header := range headers { parts := strings.SplitN(header, ":", 2) if len(parts) == 2 { @@ -615,31 +622,29 @@ func uploadFileEndpoint(filePath string, headers []string) { headersJSON, err := json.Marshal(headerMaps) if err != nil { - log.Fatalf("Error marshaling headers to JSON: %v", err) + log.Printf("Error marshaling headers to JSON: %v", err) + return } - // Create query parameters queryParams := url.Values{} queryParams.Add("headers", string(headersJSON)) - - // Append query parameters to the endpoint URL endpoint = fmt.Sprintf("%s?%s", endpoint, queryParams.Encode()) - // Log the final endpoint URL for debugging - // log.Printf("Final endpoint URL: %s", endpoint) - file, err := os.Open(filePath) if err != nil { - log.Fatalf("Error opening file: %v", err) + log.Printf("Error opening file: %v", err) + return } defer file.Close() fileInfo, err := file.Stat() if err != nil { - log.Fatalf("Error getting file info: %v", err) + log.Printf("Error getting file info: %v", err) + return } if fileInfo.Size() > 10*1024*1024 { - log.Fatalf("File size exceeds limit") + log.Printf("File size exceeds limit") + return } body := &bytes.Buffer{} @@ -650,147 +655,113 @@ func uploadFileEndpoint(filePath string, headers []string) { h.Set("Content-Type", "text/plain") part, err := writer.CreatePart(h) if err != nil { - log.Fatalf("Error creating form part: %v", err) + log.Printf("Error creating form part: %v", err) + return } - _, err = io.Copy(part, file) - if err != nil { - log.Fatalf("Error copying file content: %v", err) + if _, err := io.Copy(part, file); err != nil { + log.Printf("Error copying file content: %v", err) + return } - err = writer.Close() - if err != nil { - log.Fatalf("Error closing multipart writer: %v", err) + if err := writer.Close(); err != nil { + log.Printf("Error closing multipart writer: %v", err) + return } - req, err := http.NewRequest("POST", endpoint, body) - if err != nil { - log.Fatalf("Error creating request: %v", err) + headers = map[string]string{ + "Content-Type": writer.FormDataContentType(), + "Accept-Encoding": "gzip, deflate, br", } - req.Header.Set("Content-Type", writer.FormDataContentType()) - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - req.Header.Set("Accept-Encoding", "gzip, deflate, br") - - // log.Printf("File being uploaded: %s", filepath.Base(filePath)) - // log.Printf("Request body length: %d bytes", body.Len()) - // log.Printf("Request body content (first 200 bytes): %s", body.String()[:min(200, body.Len())]) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, body, headers) if err != nil { - log.Fatalf("Error sending request: %v", err) + log.Printf("Error making request: %v", err) + return } defer resp.Body.Close() responseBody, err := ioutil.ReadAll(resp.Body) if err != nil { - log.Fatalf("Error reading response: %v", err) + log.Printf("Error reading response: %v", err) + return } if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { - log.Fatalf("Upload failed with status code: %d", resp.StatusCode) + log.Printf("Upload failed with status code: %d", resp.StatusCode) + return } var result map[string]interface{} if err := json.Unmarshal(responseBody, &result); err != nil { - log.Fatalf("Failed to parse JSON response: %v", err) + log.Printf("Failed to parse JSON response: %v", err) + return } fileID, ok := result["fileId"].(string) if !ok { - fmt.Println("Error: fileId is not a string") + log.Printf("Error: fileId is not a string") return } getAutomationResultsByFileId(fileID) - // Print the response in a more user-friendly format - // fmt.Println("File ID: \n",result["fileId"]) - // if jsmonId, ok := result["jsmonId"].(string); ok { - // fmt.Printf("JSMON ID: %s\n", jsmonId) - // } - // if hash, ok := result["hash"].(string); ok { - // fmt.Printf("Hash: %s\n", hash) - // } - // if createdAt, ok := result["createdAt"].(float64); ok { - // timestamp := time.Unix(int64(createdAt), 0) - // fmt.Printf("Created At: %s\n", timestamp.Format(time.RFC3339)) - // } - // if message, ok := result["message"].(string); ok { - // fmt.Printf("Message: %s\n", message) - // } -} - -func min(a, b int) int { - if a < b { - return a - } - return b } func getAllAutomationResults(input string, size int) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) url := fmt.Sprintf("%s?showonly=all&inputType=domain&input=%s&size=%d", endpoint, input, size) - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return - } - - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + headers := map[string]string{} - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, url, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var result interface{} - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } prettyJSON, err := json.MarshalIndent(result, "", " ") if err != nil { - fmt.Println("Error formatting JSON:", err) + log.Printf("Error formatting JSON: %v", err) return } fmt.Println(string(prettyJSON)) } + func getScannerResults() { - endpoint := fmt.Sprintf("%s/getScannerResults", apiBaseURL) + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - return - } + endpoint := fmt.Sprintf("%s/getScannerResults", apiBaseURL) - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + headers := map[string]string{} - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, endpoint, nil, headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } @@ -802,9 +773,8 @@ func getScannerResults() { } `json:"data"` } - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &result); err != nil { + log.Printf("Error parsing JSON: %v", err) return } @@ -818,6 +788,9 @@ func getScannerResults() { func automateScanDomain(domain string, words []string) { fmt.Printf("automateScanDomain called with domain: %s and words: %v\n", domain, words) + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/automateScanDomain", apiBaseURL) requestBody := AutomateScanDomainRequest{ @@ -826,23 +799,17 @@ func automateScanDomain(domain string, words []string) { } body, err := json.Marshal(requestBody) if err != nil { - fmt.Printf("failed to marshal request body: %v\n", err) + log.Printf("failed to marshal request body: %v", err) return } - client := &http.Client{} - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(body)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(body), headers) if err != nil { - fmt.Printf("failed to send request: %v\n", err) + log.Printf("failed to send request: %v", err) return } defer resp.Body.Close() @@ -855,7 +822,7 @@ func automateScanDomain(domain string, words []string) { if err == io.EOF { break } - fmt.Printf("failed to unmarshal JSON response: %v\n", err) + log.Printf("failed to unmarshal JSON response: %v", err) return } @@ -863,39 +830,6 @@ func automateScanDomain(domain string, words []string) { } } -// func printFormattedResponse(response map[string]interface{}) { -// fmt.Println("Message:", response["message"]) -// fmt.Println("File ID:", response["fileId"]) -// fmt.Println("Trimmed Domain:", response["trimmedDomain"]) - -// scanResponse, ok := response["scanResponse"].(map[string]interface{}) -// if ok { -// fmt.Println("\nScan Response:") -// fmt.Println(" Message:", scanResponse["message"]) - -// analysisResult, ok := scanResponse["analysis_result"].(map[string]interface{}) -// if ok { -// fmt.Println("\n Analysis Result:") -// fmt.Println(" Message:", analysisResult["message"]) -// fmt.Println(" Total Chunks:", analysisResult["totalChunks"]) -// } - -// moduleScanResult, ok := scanResponse["modulescan_result"].(map[string]interface{}) -// if ok { -// fmt.Println("\n Module Scan Result:") -// fmt.Println(" Message:", moduleScanResult["message"]) -// modules, ok := moduleScanResult["data"].([]interface{}) -// if ok { -// for _, module := range modules { -// m := module.(map[string]interface{}) -// fmt.Println(" Module Name:", m["moduleName"]) -// fmt.Println(" URL:", m["url"]) -// fmt.Println() -// } -// } -// } -// } -// } func printFormattedResponse(response map[string]interface{}) { fmt.Println("Message:", response["message"]) fmt.Println("File ID:", response["fileId"]) @@ -922,35 +856,33 @@ func printFormattedResponse(response map[string]interface{}) { } } } + func callViewProfile() { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/viewProfile", apiBaseURL) - req, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - fmt.Println("Error creating request:", err) - os.Exit(1) + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodGet, endpoint, nil, headers) if err != nil { - fmt.Println("Error making request:", err) + log.Printf("Error making request: %v", err) os.Exit(1) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response body:", err) + log.Printf("Error reading response body: %v", err) os.Exit(1) } var result map[string]interface{} if err := json.Unmarshal(body, &result); err != nil { - fmt.Println("Error unmarshalling response:", err) + log.Printf("Error unmarshalling response: %v", err) os.Exit(1) } @@ -976,6 +908,9 @@ func callViewProfile() { } func compareEndpoint(id1, id2 string) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + endpoint := fmt.Sprintf("%s/compare", apiBaseURL) requestBody, err := json.Marshal(map[string]string{ @@ -983,29 +918,23 @@ func compareEndpoint(id1, id2 string) { "id2": id2, }) if err != nil { - fmt.Println("Error creating request body:", err) + log.Printf("Error creating request body: %v", err) return } - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) - if err != nil { - fmt.Println("Error creating request:", err) - return + headers := map[string]string{ + "Content-Type": "application/json", } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - client := &http.Client{} - resp, err := client.Do(req) + resp, err := makeRequest(ctx, http.MethodPost, endpoint, bytes.NewBuffer(requestBody), headers) if err != nil { - fmt.Println("Error sending request:", err) + log.Printf("Error making request: %v", err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - fmt.Printf("Unexpected status code: %d\n", resp.StatusCode) + log.Printf("Unexpected status code: %d", resp.StatusCode) body, _ := ioutil.ReadAll(resp.Body) fmt.Printf("Response: %s\n", string(body)) return @@ -1013,14 +942,13 @@ func compareEndpoint(id1, id2 string) { body, err := ioutil.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) + log.Printf("Error reading response: %v", err) return } var diffItems []DiffItem - err = json.Unmarshal(body, &diffItems) - if err != nil { - fmt.Println("Error parsing JSON:", err) + if err := json.Unmarshal(body, &diffItems); err != nil { + log.Printf("Error parsing JSON: %v", err) fmt.Printf("Response: %s\n", string(body)) return } @@ -1032,12 +960,12 @@ func compareEndpoint(id1, id2 string) { for _, item := range diffItems { if item.Added { addedCount++ - if addedCount <= 20 { // Print the first 20 additions + if addedCount <= 20 { fmt.Printf("+ %s\n", item.Value) } } else if item.Removed { removedCount++ - if removedCount <= 20 { // Print the first 20 removals + if removedCount <= 20 { fmt.Printf("- %s\n", item.Value) } } @@ -1051,4 +979,4 @@ func compareEndpoint(id1, id2 string) { if removedCount > 5 { fmt.Printf("(Only the first 20 removals are shown)\n") } -} +} \ No newline at end of file diff --git a/auth.go b/auth.go index 598a502..515fa9c 100644 --- a/auth.go +++ b/auth.go @@ -1,9 +1,10 @@ package main import ( - "io/ioutil" + "fmt" "os" "path/filepath" + "strings" ) var apiKey string @@ -11,21 +12,21 @@ var apiKey string func loadAPIKey() error { homeDir, err := os.UserHomeDir() if err != nil { - return err + return fmt.Errorf("failed to get user home directory: %w", err) } credPath := filepath.Join(homeDir, ".jsmon", "credentials") - data, err := ioutil.ReadFile(credPath) + data, err := os.ReadFile(credPath) if err != nil { - return err + return fmt.Errorf("failed to read credentials file: %w", err) } - apiKey = string(data) + apiKey = strings.TrimSpace(string(data)) return nil } func setAPIKey(key string) { - apiKey = key + apiKey = strings.TrimSpace(key) } func getAPIKey() string { diff --git a/config.go b/config.go index 0a5e360..e8fd8bc 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,27 @@ package main +import ( + "net/http" + "time" +) + const ( apiBaseURL = "https://api.jsmon.sh/api/v2" credFile = "~/.jsmon/credentials" + timeout = 10 * time.Second // ) + +var httpClient *http.Client + +func init() { + httpClient = &http.Client{ + Timeout: timeout, + } +} + +// I've added a new constant timeout to store the timeout duration. +// This timeout is used to set the Timeout field of the http.Client. +// The http.Client is then used in various parts of the code to make HTTP requests. +// This ensures that all HTTP requests have a consistent timeout setting. +// The init() function is a special function in Go that is automatically called when the package is initialized. +// It's used here to initialize the httpClient with a timeout. diff --git a/cronlib.go b/cronlib.go index 3f4c94c..c748de5 100644 --- a/cronlib.go +++ b/cronlib.go @@ -4,9 +4,10 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" + "time" ) type Response struct { @@ -14,147 +15,51 @@ type Response struct { Data string `json:"data"` } -func StartCron(cronNotification string, cronTime int64, cronType string, cronDomain string, cronDomainNotify string) { +type Domain struct { + Domain string `json:"domain"` + Notify bool `json:"notify"` +} +func StartCron(cronNotification string, cronTime int64, cronType string, cronDomain string, cronDomainNotify string) error { notification := strings.TrimSpace(cronNotification) - //split vulnerabilities vulnerabilitiesType := strings.Split(cronType, ",") cronDomains := strings.Split(cronDomain, ",") cronDomainsNotify := strings.Split(cronDomainNotify, ",") + if len(cronDomains) != len(cronDomainsNotify) { - fmt.Println("Invalid format for cronDomains and cronDomainsNotify. Use: domain1,domain2,domain3 domainNotify1,domainNotify2,domainNotify3") - return + return fmt.Errorf("invalid format for cronDomains and cronDomainsNotify. Use: domain1,domain2,domain3 domainNotify1,domainNotify2,domainNotify3") } - //trim domains and domainsNotify - for i := 0; i < len(cronDomains); i++ { - cronDomains[i] = strings.TrimSpace(cronDomains[i]) - cronDomainsNotify[i] = strings.TrimSpace(cronDomainsNotify[i]) - } - //create domains map - var domains []map[string]interface{} - for i := 0; i < len(cronDomains); i++ { - notify := strings.EqualFold(cronDomainsNotify[i], "true") - domain := map[string]interface{}{ - "domain": cronDomains[i], - "notify": notify, + domains := make([]Domain, len(cronDomains)) + for i := range cronDomains { + domains[i] = Domain{ + Domain: strings.TrimSpace(cronDomains[i]), + Notify: strings.EqualFold(strings.TrimSpace(cronDomainsNotify[i]), "true"), } - domains = append(domains, domain) } - apiKey := strings.TrimSpace(getAPIKey()) - baseUrl := apiBaseURL - client := &http.Client{} - - var method = "PUT" - var url = baseUrl + "/startCron" - req, err := http.NewRequest(method, url, nil) - if err != nil { - fmt.Printf("failed to create request: %v", err) - return - } - req.Header.Set("X-Jsmon-Key", apiKey) - req.Header.Set("Content-Type", "application/json") - data := map[string]interface{}{ "notificationChannel": notification, "vulnerabilitiesType": vulnerabilitiesType, "time": cronTime, "domains": domains, } - jsonData, err := json.Marshal(data) - if err != nil { - fmt.Printf("failed to marshal JSON: %v", err) - return - } - - req.Body = ioutil.NopCloser(bytes.NewReader(jsonData)) - - resp, err := client.Do(req) - if err != nil { - fmt.Printf("failed to send request: %v", err) - return - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Printf("failed to read response body: %v", err) - return - } - var response Response - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("failed to unmarshal JSON response: %v", err) - return - } - - fmt.Println("Message:", response.Message) + return sendRequest("PUT", "/startCron", data) } -func StopCron() { - apiKey := strings.TrimSpace(getAPIKey()) - baseUrl := apiBaseURL - client := &http.Client{} - var method = "PUT" - var url = baseUrl + "/stopCron" - req, err := http.NewRequest(method, url, nil) - if err != nil { - fmt.Printf("failed to create request: %v", err) - return - } - req.Header.Set("X-Jsmon-Key", apiKey) - req.Header.Set("Content-Type", "application/json") - - resp, err := client.Do(req) - if err != nil { - fmt.Printf("failed to send request: %v", err) - return - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Printf("failed to read response body: %v", err) - return - } - - var response Response - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("failed to unmarshal JSON response: %v", err) - return - } - - fmt.Println("Message:", response.Message) - +func StopCron() error { + return sendRequest("PUT", "/stopCron", nil) } -func UpdateCron(cronNotification string, cronType string, cronDomain string, cronDomainNotify string, cronTime int64) { - apiKey := strings.TrimSpace(getAPIKey()) - baseUrl := apiBaseURL - - client := &http.Client{} - var method = "PUT" - var url = baseUrl + "/updateCron" - - req, err := http.NewRequest(method, url, nil) - if err != nil { - fmt.Printf("failed to create request: %v", err) - return - } - - req.Header.Set("X-Jsmon-Key", apiKey) - req.Header.Set("Content-Type", "application/json") +func UpdateCron(cronNotification string, cronType string, cronDomain string, cronDomainNotify string, cronTime int64) error { + data := make(map[string]interface{}) - data := map[string]interface{}{} if cronNotification != "" { data["notificationChannel"] = cronNotification } if cronType != "" { - vulnerabilitiesType := strings.Split(cronType, ",") - data["vulnerabilitiesType"] = vulnerabilitiesType + data["vulnerabilitiesType"] = strings.Split(cronType, ",") } if cronTime != 0 { data["time"] = cronTime @@ -163,54 +68,60 @@ func UpdateCron(cronNotification string, cronType string, cronDomain string, cro cronDomains := strings.Split(cronDomain, ",") cronDomainsNotify := strings.Split(cronDomainNotify, ",") if len(cronDomains) != len(cronDomainsNotify) { - fmt.Println("Invalid format for cronDomains and cronDomainsNotify. Use: domain1,domain2,domain3 domainNotify1,domainNotify2,domainNotify3") - return + return fmt.Errorf("invalid format for cronDomains and cronDomainsNotify. Use: domain1,domain2,domain3 domainNotify1,domainNotify2,domainNotify3") } - //trim domains and domainsNotify - for i := 0; i < len(cronDomains); i++ { - cronDomains[i] = strings.TrimSpace(cronDomains[i]) - cronDomainsNotify[i] = strings.TrimSpace(cronDomainsNotify[i]) - } - //create domains map - var domains []map[string]interface{} - for i := 0; i < len(cronDomains); i++ { - notify := strings.EqualFold(cronDomainsNotify[i], "true") - domain := map[string]interface{}{ - "domain": cronDomains[i], - "notify": notify, + + domains := make([]Domain, len(cronDomains)) + for i := range cronDomains { + domains[i] = Domain{ + Domain: strings.TrimSpace(cronDomains[i]), + Notify: strings.EqualFold(strings.TrimSpace(cronDomainsNotify[i]), "true"), } - domains = append(domains, domain) } data["domains"] = domains } - jsonData, err := json.Marshal(data) + return sendRequest("PUT", "/updateCron", data) +} + +func sendRequest(method, endpoint string, data interface{}) error { + apiKey := strings.TrimSpace(getAPIKey()) + url := apiBaseURL + endpoint + + var body io.Reader + if data != nil { + jsonData, err := json.Marshal(data) + if err != nil { + return fmt.Errorf("failed to marshal JSON: %w", err) + } + body = bytes.NewReader(jsonData) + } + + req, err := http.NewRequest(method, url, body) if err != nil { - fmt.Printf("failed to marshal JSON: %v", err) - return + return fmt.Errorf("failed to create request: %w", err) } - req.Body = ioutil.NopCloser(bytes.NewReader(jsonData)) + req.Header.Set("X-Jsmon-Key", apiKey) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { - fmt.Printf("failed to send request: %v", err) - return + return fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + responseBody, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("failed to read response body: %v", err) - return + return fmt.Errorf("failed to read response body: %w", err) } + var response Response - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("failed to unmarshal JSON response: %v", err) - return + if err := json.Unmarshal(responseBody, &response); err != nil { + return fmt.Errorf("failed to unmarshal JSON response: %w", err) } fmt.Println("Message:", response.Message) - + return nil } diff --git a/extractApiPaths.go b/extractApiPaths.go index 232dbf7..6998ab5 100644 --- a/extractApiPaths.go +++ b/extractApiPaths.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) @@ -40,14 +40,16 @@ func getApiPaths(domains []string) { defer resp.Body.Close() // Read response - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response body: %v\n", err) return } // Parse response - var response map[string]interface{} + var response struct { + ApiPaths []string `json:"apiPaths"` + } err = json.Unmarshal(body, &response) if err != nil { fmt.Printf("Failed to unmarshal JSON response: %v\n", err) @@ -55,13 +57,7 @@ func getApiPaths(domains []string) { } // Access and print API paths - if apiPaths, ok := response["apiPaths"].([]interface{}); ok { - for _, path := range apiPaths { - if pathStr, ok := path.(string); ok { - fmt.Println(pathStr) - } else { - fmt.Println("Error: Invalid type in 'apiPaths'") - } - } + for _, path := range response.ApiPaths { + fmt.Println(path) } } diff --git a/getDomainStatus.go b/getDomainStatus.go index 654d1a6..23d43a1 100644 --- a/getDomainStatus.go +++ b/getDomainStatus.go @@ -1,30 +1,36 @@ - package main import ( "encoding/json" "fmt" + "io" "net/http" "strings" - "io" + "time" ) +// Define a struct for the domain status +type DomainStatus struct { + DomainName string `json:"domainName"` + Status string `json:"status"` + ExpiryDate string `json:"expiryDate"` +} -func getAllDomainsStatus(input string, size int){ +func getAllDomainsStatus(input string, size int) { endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "domainStatus", input, size, 0, "desc", "createdAt") + url := fmt.Sprintf("%s?showonly=domainStatus&inputType=domain&input=%s&size=%d&start=0&sortOrder=desc&sortBy=createdAt", endpoint, input, size) - // create request + // Create request req, err := http.NewRequest("GET", url, nil) if err != nil { - fmt.Printf("Failed to create request") + fmt.Printf("Failed to create request: %v\n", err) return } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // send request - client := &http.Client{} + // Send request + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { fmt.Printf("Failed to send request: %v\n", err) @@ -32,70 +38,78 @@ func getAllDomainsStatus(input string, size int){ } defer resp.Body.Close() - // read response + // Read response body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response body: %v\n", err) return } - // parse response + // Parse response var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { + if err := json.Unmarshal(body, &response); err != nil { fmt.Printf("Failed to unmarshal JSON response: %v\n", err) return } - // fmt.Println(response, "HELLP") - // access urls map results, err := extractResults(response) - if err != nil { - fmt.Println(err) - return - } - - // fmt.Println("SOME OUTPUT FROM RESULTS", results) - - domainStatus := processExtractedDomains(results) - // fmt.Println("domain Status", domainStatus) - for _, domain := range domainStatus { - fmt.Println(domain) - } + if err != nil { + fmt.Println(err) + return + } + domainStatuses := processExtractedDomains(results) + for _, status := range domainStatuses { + fmt.Println(status) + } } + func extractResults(response map[string]interface{}) ([]interface{}, error) { - if results, ok := response["results"].([]interface{}); ok { - return results, nil - } - return nil, fmt.Errorf("no data found in response") + results, ok := response["results"].([]interface{}) + if !ok { + return nil, fmt.Errorf("no data found in response") + } + return results, nil } func processExtractedDomains(results []interface{}) []string { - output := make([]string, 0) - - for _, result := range results { - if resultMap, ok := result.(map[string]interface{}); ok { - // Access 'extractedDomainsStatus' - - if extractedDomainsStatus, ok := resultMap["extractedDomainsStatus"].([]interface{}); ok { - domainStatusResult := processDomainStatus(extractedDomainsStatus) - output = append(output, domainStatusResult...) - } - } - } - return output + var output []string + + for _, result := range results { + resultMap, ok := result.(map[string]interface{}) + if !ok { + continue + } + + extractedDomainsStatus, ok := resultMap["extractedDomainsStatus"].([]interface{}) + if !ok { + continue + } + + output = append(output, processDomainStatus(extractedDomainsStatus)...) + } + + return output } func processDomainStatus(extractedDomainsStatus []interface{}) []string { - output := make([]string, 0) + var output []string for _, domainArray := range extractedDomainsStatus { - if domains, ok := domainArray.(map[string]interface{}); ok { - - record := fmt.Sprintf("%s | %s | %s", domains["domainName"], domains["status"], domains["expiryDate"]) - fmt.Println(record) + domains, ok := domainArray.(map[string]interface{}) + if !ok { + continue + } + + status := DomainStatus{ + DomainName: fmt.Sprintf("%v", domains["domainName"]), + Status: fmt.Sprintf("%v", domains["status"]), + ExpiryDate: fmt.Sprintf("%v", domains["expiryDate"]), } + + record := fmt.Sprintf("%s | %s | %s", status.DomainName, status.Status, status.ExpiryDate) + output = append(output, record) } + return output -} \ No newline at end of file +} diff --git a/getDomainUrls.go b/getDomainUrls.go index d6c4712..bfc2e0c 100644 --- a/getDomainUrls.go +++ b/getDomainUrls.go @@ -4,14 +4,15 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) -// Function to get domain URLs +// getDomainUrls fetches and prints domain URLs for the given domains func getDomainUrls(domains []string) { endpoint := fmt.Sprintf("%s/getDomainsUrls", apiBaseURL) + requestBody, err := json.Marshal(map[string]interface{}{ "domains": domains, }) @@ -20,8 +21,7 @@ func getDomainUrls(domains []string) { return } - // Create request - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) + req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(requestBody)) if err != nil { fmt.Printf("Failed to create request: %v\n", err) return @@ -29,7 +29,6 @@ func getDomainUrls(domains []string) { req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Send request client := &http.Client{} resp, err := client.Do(req) if err != nil { @@ -38,42 +37,31 @@ func getDomainUrls(domains []string) { } defer resp.Body.Close() - // Read response - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response body: %v\n", err) return } - // Parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { + var response struct { + Data struct { + ExtractedDomains []string `json:"extractedDomains"` + ExtractedUrls []string `json:"extractedUrls"` + } `json:"data"` + } + + if err := json.Unmarshal(body, &response); err != nil { fmt.Printf("Failed to unmarshal JSON response: %v\n", err) return } - // Extract data - if data, ok := response["data"].(map[string]interface{}); ok { - - // Print extracted domains - if extractedDomains, ok := data["extractedDomains"].([]interface{}); ok { - for _, domain := range extractedDomains { - if domainStr, ok := domain.(string); ok { - fmt.Println(domainStr) - } - } - } + // Print extracted domains + for _, domain := range response.Data.ExtractedDomains { + fmt.Println(domain) + } - // Print extracted URLs - if extractedUrls, ok := data["extractedUrls"].([]interface{}); ok { - for _, url := range extractedUrls { - if urlStr, ok := url.(string); ok { - fmt.Println(urlStr) - } - } - } - } else { - fmt.Println("Error: 'data' field not found or not in expected format") + // Print extracted URLs + for _, url := range response.Data.ExtractedUrls { + fmt.Println(url) } } diff --git a/getEmails.go b/getEmails.go index 4047cbd..666684c 100644 --- a/getEmails.go +++ b/getEmails.go @@ -4,67 +4,51 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) -// Function to get emails -func getEmails(domains []string) { - // Prepare request data +// getEmails retrieves emails for the given domains +func getEmails(domains []string) error { endpoint := fmt.Sprintf("%s/getEmails", apiBaseURL) requestBody, err := json.Marshal(map[string]interface{}{ "domains": domains, }) if err != nil { - fmt.Println("Error creating request body:", err) - return + return fmt.Errorf("error creating request body: %w", err) } - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) + req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(requestBody)) if err != nil { - fmt.Println("Error creating request:", err) - return + return fmt.Errorf("error creating request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Send the request client := &http.Client{} resp, err := client.Do(req) if err != nil { - fmt.Println("Error sending request:", err) - return + return fmt.Errorf("error sending request: %w", err) } defer resp.Body.Close() - // Read the response - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { - fmt.Println("Error reading response:", err) - return + return fmt.Errorf("error reading response: %w", err) } - // Parse and print JSON response - var result map[string]interface{} - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) - return + var result struct { + Emails []string `json:"emails"` } - - // Pretty print JSON - emails, ok := result["emails"].([]interface{}) - if !ok { - fmt.Println("Error: 'email' field not found or not in expected format") - return + if err := json.Unmarshal(body, &result); err != nil { + return fmt.Errorf("error parsing JSON: %w", err) } - for _, path := range emails { - if pathStr, ok := path.(string); ok { - fmt.Println(pathStr) - } else { - fmt.Println("Error: Invalid type in 'emails'") - } + + for _, email := range result.Emails { + fmt.Println(email) } + + return nil } diff --git a/getExtractedUrls.go b/getExtractedUrls.go index 2ca6f7d..b68db94 100644 --- a/getExtractedUrls.go +++ b/getExtractedUrls.go @@ -3,352 +3,156 @@ package main import ( "encoding/json" "fmt" + "io" "net/http" "strings" - "io" urlPkg "net/url" "path/filepath" ) -func getAllFileExtensionUrls(input string, extensions []string, size int) { - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "fileExtensionUrls", input ,size, 0, "desc", "fileExtensionUrls") +// Common function to make API requests +func makeAPIRequest(endpoint, showonly, input string, size int, sortBy string) ([]interface{}, error) { + url := fmt.Sprintf("%s/getAllAutomationResults?showonly=%s&inputType=domain&input=%s&size=%d&start=0&sortOrder=desc&sortBy=%s", + apiBaseURL, showonly, input, size, sortBy) - // create request req, err := http.NewRequest("GET", url, nil) if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return + return nil, fmt.Errorf("failed to create request: %v", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // send request client := &http.Client{} resp, err := client.Do(req) if err != nil { - fmt.Printf("Failed to get data") - return + return nil, fmt.Errorf("failed to get data: %v", err) } defer resp.Body.Close() - // read response body, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("Failed to read response body: %v\n", err) - return + return nil, fmt.Errorf("failed to read response body: %v", err) } - // parse response var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("Failed to unmarshal JSON response: %v\n", err) - return + if err := json.Unmarshal(body, &response); err != nil { + return nil, fmt.Errorf("failed to unmarshal JSON response: %v", err) } - // maping the extensions to a map, while converting pdf to .pdf - extensionsMap := make(map[string]struct{}, 0) - for _, ext := range extensions { - extensionsMap["." + ext] = struct{}{} + results, ok := response["results"].([]interface{}) + if !ok { + return nil, fmt.Errorf("data not found or not in expected format") } - // fmt.Println(response, "HELLP") - // access urls map - results, err := extractResultsFromResponse(response) + return results, nil +} + +// Common function to extract URLs from results +func extractURLs(results []interface{}, field string) []string { + var urls []string + for _, result := range results { + if resultMap, ok := result.(map[string]interface{}); ok { + if fieldUrls, ok := resultMap[field].([]interface{}); ok { + for _, urlStr := range fieldUrls { + if url, ok := urlStr.(string); ok { + urls = append(urls, url) + } + } + } + } + } + return urls +} + +func getAllFileExtensionUrls(input string, extensions []string, size int) { + results, err := makeAPIRequest(apiBaseURL, "fileExtensionUrls", input, size, "fileExtensionUrls") if err != nil { + fmt.Printf("Error: %v\n", err) return } - - urls := captureResultsFromResponse(results, "fileExtensionUrls") - new_urls := make([]string, 0) + + urls := extractURLs(results, "fileExtensionUrls") if len(extensions) > 0 { + extensionsMap := make(map[string]struct{}) + for _, ext := range extensions { + extensionsMap["."+ext] = struct{}{} + } + + var filteredUrls []string for _, urlStr := range urls { parsedURL, err := urlPkg.Parse(urlStr) if err != nil { continue } ext := filepath.Ext(parsedURL.Path) - if _, ok := extensionsMap[ext]; ok { - new_urls = append(new_urls, urlStr) + filteredUrls = append(filteredUrls, urlStr) } } - urls = new_urls + urls = filteredUrls } + sendOutputToStdout(urls) } func getAllSocialMediaUrls(input string, size int) { - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "socialMediaUrls", input, size, 0, "desc", "createdAt") - - // fmt.Println("URL :", url) - // create request - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // send request - client := &http.Client{} - resp, err := client.Do(req) + results, err := makeAPIRequest(apiBaseURL, "socialMediaUrls", input, size, "createdAt") if err != nil { - fmt.Printf("Failed to get data") + fmt.Printf("Error: %v\n", err) return } - defer resp.Body.Close() - // read response - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("Failed to read data") - return - } - - // parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("Failed to unmarshal JSON response: %v\n", err) - return - } - - // fmt.Println(response, "HELLP") - // access urls map - - results, err := extractResultsFromResponse(response) - if err != nil { - return - } - - urls := captureResultsFromResponse(results, "socialMediaUrls") - + urls := extractURLs(results, "socialMediaUrls") sendOutputToStdout(urls) } func getAllQueryParamsUrls(input string, size int) { - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "queryParamsUrls", input, size, 0, "desc", "createdAt") - - // create request - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // send request - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - fmt.Printf("Failed to get data") - return - } - defer resp.Body.Close() - - // read response - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("Failed to read data") - return - } - - // parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) + results, err := makeAPIRequest(apiBaseURL, "queryParamsUrls", input, size, "createdAt") if err != nil { - fmt.Printf("Failed to parse data") + fmt.Printf("Error: %v\n", err) return } - // parse the response from the API call - results, err := extractResultsFromResponse(response) - if err != nil { - return - } - - urls := captureResultsFromResponse(results, "queryParamsUrls") + urls := extractURLs(results, "queryParamsUrls") sendOutputToStdout(urls) } func getAllLocalhostUrls(input string, size int) { - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "localhostUrls", input, size, 0, "desc", "localhostUrls") - - // create request - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Printf("Failed to create request") - return - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // send request - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - fmt.Printf("Failed to get data") - return - } - defer resp.Body.Close() - - // read response - body, err := io.ReadAll(resp.Body) + results, err := makeAPIRequest(apiBaseURL, "localhostUrls", input, size, "localhostUrls") if err != nil { - fmt.Printf("Failed to read data") + fmt.Printf("Error: %v\n", err) return } - // parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("Failed to parse data") - return - } - - // parse the response from the API call - // parse the response from the API call - results, err := extractResultsFromResponse(response) - if err != nil { - return - } - - urls := captureResultsFromResponse(results, "localhostUrls") + urls := extractURLs(results, "localhostUrls") sendOutputToStdout(urls) } func getAllFilteredPortUrls(input string, size int) { - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "filteredPortUrls", input, size, 0, "desc", "filteredPortUrls") - - // create request - req, err := http.NewRequest("GET", url, nil) + results, err := makeAPIRequest(apiBaseURL, "filteredPortUrls", input, size, "filteredPortUrls") if err != nil { - fmt.Printf("Failed to create request") - return - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // send request - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - fmt.Printf("Failed to get data") - return - } - defer resp.Body.Close() - - // read response - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("Failed to read data") - return - } - - // parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("Failed to parse data") + fmt.Printf("Error: %v\n", err) return } - // parse the response from the API call - results, err := extractResultsFromResponse(response) - if err != nil { - return - } - - urls := captureResultsFromResponse(results, "filteredPortUrls") + urls := extractURLs(results, "filteredPortUrls") sendOutputToStdout(urls) } -func getAllS3DomainsInvalid(input string, size int){ - endpoint := fmt.Sprintf("%s/getAllAutomationResults", apiBaseURL) - url := fmt.Sprintf("%s?showonly=%s&inputType=domain&input=%s&size=%d&start=%d&sortOrder=%s&sortBy=%s", endpoint, "s3DomainsInvalid", input, size, 0, "desc", "s3DomainsInvalid") - - // create request - req, err := http.NewRequest("GET", url, nil) - if err != nil { - fmt.Printf("Failed to create request") - return - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - - // send request - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - fmt.Printf("Failed to get data") - return - } - defer resp.Body.Close() - - // read response - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Printf("Failed to read data") - return - } - - // parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) +func getAllS3DomainsInvalid(input string, size int) { + results, err := makeAPIRequest(apiBaseURL, "s3DomainsInvalid", input, size, "s3DomainsInvalid") if err != nil { - fmt.Printf("Failed to parse data") + fmt.Printf("Error: %v\n", err) return } - // parse the response from the API call - results, err := extractResultsFromResponse(response) - if err != nil { - return - } - - urls := captureResultsFromResponse(results, "s3DomainsInvalid") + urls := extractURLs(results, "s3DomainsInvalid") sendOutputToStdout(urls) } -func extractResultsFromResponse(response map[string]interface{}) ([]interface{}, error) { - if results, ok := response["results"].([]interface{}); ok { - return results, nil - } - return nil, fmt.Errorf("data not found or not in expected format") -} - -func captureResultsFromResponse(results []interface{}, field string) []string { - output := make([]string, 0) - for _, result := range results { - if resultMap, ok := result.(map[string]interface{}); ok { - // Access 'extractedDomainsStatus' - if fieldUrls, ok := resultMap[field].([]interface{}); ok { - for _, urlStr := range fieldUrls { - if url, ok := urlStr.(string); ok { - // fmt.Println(url) - output = append(output, url) - } else { - fmt.Println("Found Invalid URL format") - } - } - } - } - } - return output -} - func sendOutputToStdout(output []string) { for _, urlStr := range output { fmt.Println(urlStr) } -} \ No newline at end of file +} diff --git a/getGqlOps.go b/getGqlOps.go index 0d4976d..7c77115 100644 --- a/getGqlOps.go +++ b/getGqlOps.go @@ -2,44 +2,44 @@ package main import ( "bytes" + "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" + "time" ) -func getGqlOps(domains []string) { +func getGqlOps(ctx context.Context, domains []string) error { endpoint := fmt.Sprintf("%s/getGqlOps", apiBaseURL) - requestBody, err := json.Marshal(map[string]interface{}{ + + var requestBody bytes.Buffer + if err := json.NewEncoder(&requestBody).Encode(map[string]interface{}{ "domains": domains, - }) - if err != nil { - fmt.Printf("Failed to marshal request body: %v\n", err) - return + }); err != nil { + return fmt.Errorf("failed to marshal request body: %w", err) } - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) + req, err := http.NewRequestWithContext(ctx, "POST", endpoint, &requestBody) if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return + return fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - client := &http.Client{} + client := &http.Client{Timeout: 30 * time.Second} resp, err := client.Do(req) if err != nil { - fmt.Printf("Failed to send request: %v\n", err) - return + return fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("Failed to read response: %v\n", err) - return + return fmt.Errorf("failed to read response: %w", err) } fmt.Println(string(body)) + return nil } diff --git a/getIps.go b/getIps.go index 306237b..84bf8f4 100644 --- a/getIps.go +++ b/getIps.go @@ -4,33 +4,40 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) -// Function to get IP addresses based on domains +// IPAddresses represents the structure of the IP addresses in the response +type IPAddresses struct { + IPv4 []string `json:"ipv4Addresses"` + IPv6 []string `json:"ipv6Addresses"` +} + +// Response represents the structure of the API response +type Response struct { + IPAddresses IPAddresses `json:"ipAddresses"` +} + +// getAllIps retrieves IP addresses based on given domains func getAllIps(domains []string) { - // Prepare request data endpoint := fmt.Sprintf("%s/getIps", apiBaseURL) - requestBody, err := json.Marshal(map[string]interface{}{ - "domains": domains, - }) + requestBody, err := json.Marshal(map[string][]string{"domains": domains}) if err != nil { fmt.Printf("Failed to marshal request body: %v\n", err) return } - // Create request - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) + req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(requestBody)) if err != nil { fmt.Printf("Failed to create request: %v\n", err) return } + req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Send request client := &http.Client{} resp, err := client.Do(req) if err != nil { @@ -39,49 +46,38 @@ func getAllIps(domains []string) { } defer resp.Body.Close() - // Read response - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response body: %v\n", err) return } - // Parse response - var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { + var response Response + if err := json.Unmarshal(body, &response); err != nil { fmt.Printf("Failed to unmarshal JSON response: %v\n", err) return } - // Access ipAddresses map - if ipData, ok := response["ipAddresses"].(map[string]interface{}); ok { - // Extract and print IPv4 addresses - if ipv4, ok := ipData["ipv4Addresses"].([]interface{}); ok { - for _, ip := range ipv4 { - if ipStr, ok := ip.(string); ok { - fmt.Println(ipStr) - } else { - fmt.Println("Error: Invalid type in 'ipv4Addresses'") - } - } - } else { - fmt.Println("No 'ipv4Addresses' found or not in expected format") + printIPAddresses(response.IPAddresses) +} + +// printIPAddresses prints the IPv4 and IPv6 addresses +func printIPAddresses(ipAddresses IPAddresses) { + if len(ipAddresses.IPv4) > 0 { + fmt.Println("IPv4 Addresses:") + for _, ip := range ipAddresses.IPv4 { + fmt.Println(ip) } + } else { + fmt.Println("No IPv4 addresses found") + } - // Extract and print IPv6 addresses - if ipv6, ok := ipData["ipv6Addresses"].([]interface{}); ok { - for _, ip := range ipv6 { - if ipStr, ok := ip.(string); ok { - fmt.Println(ipStr) - } else { - fmt.Println("Error: Invalid type in 'ipv6Addresses'") - } - } - } else { - fmt.Println("No 'ipv6Addresses' found or not in expected format") + if len(ipAddresses.IPv6) > 0 { + fmt.Println("IPv6 Addresses:") + for _, ip := range ipAddresses.IPv6 { + fmt.Println(ip) } } else { - fmt.Println("Error: 'ipAddresses' field not found or not in expected format") + fmt.Println("No IPv6 addresses found") } } diff --git a/getResultByInput.go b/getResultByInput.go index d80714e..5e6698a 100644 --- a/getResultByInput.go +++ b/getResultByInput.go @@ -1,49 +1,72 @@ package main + import ( + "context" + "encoding/json" "fmt" - "strings" + "io" + "log" "net/http" - "io/ioutil" + "strings" + "time" ) -func getAutomationResultsByInput(inputType, value string){ - endpoint := fmt.Sprintf("%s/getAllJsUrlsResults?inputType=%s&input=%s", apiBaseURL, inputType, value) +// AutomationResult represents the structure of the API response +type AutomationResult struct { + // Add fields based on the actual response structure + // For example: + // JsmonID string `json:"jsmonId"` + // URL string `json:"url"` + // ... other fields +} +func getAutomationResultsByInput(ctx context.Context, inputType, value string) ([]AutomationResult, error) { + endpoint := fmt.Sprintf("%s/getAllJsUrlsResults?inputType=%s&input=%s", apiBaseURL, inputType, value) - // Create a new HTTP request with the GET method - req, err := http.NewRequest("GET", endpoint, nil) // No need for request body in GET + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return + return nil, fmt.Errorf("failed to create request: %w", err) } - // Set necessary headers req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) // Trim any whitespace from the API key + req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + + client := &http.Client{ + Timeout: 30 * time.Second, + } - // Create an HTTP client and make the request - client := &http.Client{} resp, err := client.Do(req) if err != nil { - fmt.Printf("Failed to send request: %v\n", err) - return + return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() - // Read the response body - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response: %w", err) + } + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return nil, fmt.Errorf("unexpected status code: %d, response: %s", resp.StatusCode, string(body)) + } + + var results []AutomationResult + if err := json.Unmarshal(body, &results); err != nil { + return nil, fmt.Errorf("failed to parse response: %w", err) + } + + return results, nil +} + +// Usage example +func main() { + ctx := context.Background() + results, err := getAutomationResultsByInput(ctx, "someInputType", "someValue") if err != nil { - fmt.Printf("Failed to read response: %v\n", err) - return + log.Fatalf("Error getting automation results: %v", err) } - // Check if the response is successful (Status Code: 2xx) - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - // Print the response with all fields related to the jsmonId - fmt.Println(string(body)) - } else { - fmt.Printf("Error: Received status code %d\n", resp.StatusCode) - fmt.Println("Response:", string(body)) // Print the response even if it's an error + for _, result := range results { + log.Printf("Result: %+v", result) } - -} \ No newline at end of file +} diff --git a/getResultsByFileId.go b/getResultsByFileId.go index 04b6164..170cc44 100644 --- a/getResultsByFileId.go +++ b/getResultsByFileId.go @@ -1,82 +1,75 @@ package main import ( + "context" + "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" - "encoding/json" + "time" +) + +const ( + timeout = 30 * time.Second + endpointFormat = "%s/getAllAutomationResults?inputType=fileid&input=%s&showonly=all" + contentTypeJSON = "application/json" ) -// Function to fetch automation results for a given jsmonId -func getAutomationResultsByFileId(fileId string) { - // Define the API base URL and endpoint, appending the jsmonId as a query parameter - endpoint := fmt.Sprintf("%s/getAllAutomationResults?inputType=fileid&input=%s&showonly=all", apiBaseURL, fileId) +type APIResponse struct { + Results []map[string]interface{} `json:"results"` +} + +// getAutomationResultsByFileId fetches automation results for a given fileId +func getAutomationResultsByFileId(fileId string) error { + if fileId == "" { + return fmt.Errorf("fileId cannot be empty") + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + endpoint := fmt.Sprintf(endpointFormat, apiBaseURL, fileId) - // Create a new HTTP request with the GET method - req, err := http.NewRequest("GET", endpoint, nil) // No need for request body in GET + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) if err != nil { - fmt.Printf("Failed to create request: %v\n", err) - return + return fmt.Errorf("failed to create request: %w", err) } - // Set necessary headers - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) // Trim any whitespace from the API key + req.Header.Set("Content-Type", contentTypeJSON) + req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Create an HTTP client and make the request client := &http.Client{} resp, err := client.Do(req) if err != nil { - fmt.Printf("Failed to send request: %v\n", err) - return + return fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() - // Read the response body - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("Failed to read response: %v\n", err) - return + return fmt.Errorf("failed to read response: %w", err) } - // Check if the response is successful (Status Code: 2xx) - if resp.StatusCode >= 200 && resp.StatusCode < 300 { - // Print the response with all fields related to the jsmonId - var result interface{} - err = json.Unmarshal(body, &result) - if err != nil { - fmt.Println("Error parsing JSON:", err) - return + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("received non-success status code %d: %s", resp.StatusCode, string(body)) } - // Assert that result is of type map[string]interface{} - if resMap, ok := result.(map[string]interface{}); ok { - // Access the "results" key - if results, ok := resMap["results"].([]interface{}); ok { - if len(results) > 0 { - // Access the first element - firstElement := results[0] + var apiResp APIResponse + if err := json.Unmarshal(body, &apiResp); err != nil { + return fmt.Errorf("error parsing JSON: %w", err) + } - // Print the first element as a pretty JSON string - prettyJSON, err := json.MarshalIndent(firstElement, "", " ") - if err != nil { - fmt.Println("Error formatting JSON:", err) - return - } + if len(apiResp.Results) == 0 { + fmt.Println("Results array is empty.") + return nil + } - fmt.Println(string(prettyJSON)) - } else { - fmt.Println("Results array is empty.") - } - } else { - fmt.Println("results is not of type []interface{}") - } - } else { - fmt.Println("result is not of type map[string]interface{}") - } - } else { - fmt.Printf("Error: Received status code %d\n", resp.StatusCode) - fmt.Println("Response:", string(body)) // Print the response even if it's an error + prettyJSON, err := json.MarshalIndent(apiResp.Results[0], "", " ") + if err != nil { + return fmt.Errorf("error formatting JSON: %w", err) } + + fmt.Println(string(prettyJSON)) + return nil } diff --git a/getResultsByJsmonId.go b/getResultsByJsmonId.go index 3a57451..5adf9a5 100644 --- a/getResultsByJsmonId.go +++ b/getResultsByJsmonId.go @@ -1,82 +1,74 @@ package main import ( + "encoding/json" "fmt" "io/ioutil" "net/http" "strings" - "encoding/json" ) +const ( + inputTypeParam = "jsmonid" + showOnlyParam = "all" +) + +type APIResponse struct { + Results []map[string]interface{} `json:"results"` +} + // Function to fetch automation results for a given jsmonId func getAutomationResultsByJsmonId(jsmonId string) { - // Define the API base URL and endpoint, appending the jsmonId as a query parameter - endpoint := fmt.Sprintf("%s/getAllAutomationResults?inputType=jsmonid&input=%s&showonly=all", apiBaseURL, jsmonId) + endpoint := fmt.Sprintf("%s/getAllAutomationResults?inputType=%s&input=%s&showonly=%s", apiBaseURL, inputTypeParam, jsmonId, showOnlyParam) - // Create a new HTTP request with the GET method - req, err := http.NewRequest("GET", endpoint, nil) // No need for request body in GET + req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { fmt.Printf("Failed to create request: %v\n", err) return } - // Set necessary headers req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) // Trim any whitespace from the API key + req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Create an HTTP client and make the request - client := &http.Client{} - resp, err := client.Do(req) + resp, err := httpClient.Do(req) if err != nil { fmt.Printf("Failed to send request: %v\n", err) return } defer resp.Body.Close() - // Read the response body body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response: %v\n", err) return } - // Check if the response is successful (Status Code: 2xx) if resp.StatusCode >= 200 && resp.StatusCode < 300 { - // Print the response with all fields related to the jsmonId - var result interface{} - err = json.Unmarshal(body, &result) - if err != nil { + printFirstResult(body) + } else { + fmt.Printf("Error: Received status code %d\n", resp.StatusCode) + fmt.Println("Response:", string(body)) + } +} + +func printFirstResult(body []byte) { + var apiResp APIResponse + if err := json.Unmarshal(body, &apiResp); err != nil { fmt.Println("Error parsing JSON:", err) return } - // Assert that result is of type map[string]interface{} - if resMap, ok := result.(map[string]interface{}); ok { - // Access the "results" key - if results, ok := resMap["results"].([]interface{}); ok { - if len(results) > 0 { - // Access the first element - firstElement := results[0] - - // Print the first element as a pretty JSON string - prettyJSON, err := json.MarshalIndent(firstElement, "", " ") - if err != nil { - fmt.Println("Error formatting JSON:", err) - return - } + if len(apiResp.Results) == 0 { + fmt.Println("Results array is empty.") + return + } - fmt.Println(string(prettyJSON)) - } else { - fmt.Println("Results array is empty.") - } - } else { - fmt.Println("results is not of type []interface{}") - } - } else { - fmt.Println("result is not of type map[string]interface{}") - } - } else { - fmt.Printf("Error: Received status code %d\n", resp.StatusCode) - fmt.Println("Response:", string(body)) // Print the response even if it's an error + prettyJSON, err := json.MarshalIndent(apiResp.Results[0], "", " ") + if err != nil { + fmt.Println("Error formatting JSON:", err) + return } + + fmt.Println(string(prettyJSON)) } + diff --git a/getS3Domains.go b/getS3Domains.go index 70f2de3..650430a 100644 --- a/getS3Domains.go +++ b/getS3Domains.go @@ -4,15 +4,15 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" ) -// Function to get API paths based on domains +// getS3Domains retrieves API paths based on domains func getS3Domains(domains []string) { - // Prepare request data endpoint := fmt.Sprintf("%s/getS3Domains", apiBaseURL) + requestBody, err := json.Marshal(map[string]interface{}{ "domains": domains, }) @@ -21,51 +21,59 @@ func getS3Domains(domains []string) { return } - // Create request - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(requestBody)) + req, err := createRequest(endpoint, requestBody) if err != nil { fmt.Printf("Failed to create request: %v\n", err) return } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) - // Send request - client := &http.Client{} - resp, err := client.Do(req) + resp, err := sendRequest(req) if err != nil { fmt.Printf("Failed to send request: %v\n", err) return } defer resp.Body.Close() - // Read response - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("Failed to read response body: %v\n", err) return } - // Parse response var response map[string]interface{} - err = json.Unmarshal(body, &response) - if err != nil { + if err := json.Unmarshal(body, &response); err != nil { fmt.Printf("Failed to unmarshal JSON response: %v\n", err) return } - // Extract and print the data in the desired format - // message, ok := response["message"].(string) - // if ok { - // fmt.Println(message) - // } + printS3Domains(response) +} +func createRequest(endpoint string, requestBody []byte) (*http.Request, error) { + req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(requestBody)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + return req, nil +} + +func sendRequest(req *http.Request) (*http.Response, error) { + client := &http.Client{} + return client.Do(req) +} + +func printS3Domains(response map[string]interface{}) { s3Domains, ok := response["s3Domains"].([]interface{}) - if ok && len(s3Domains) > 0 { - for _, domain := range s3Domains { - if domainStr, ok := domain.(string); ok { - fmt.Println(domainStr) - } + if !ok || len(s3Domains) == 0 { + fmt.Println("No S3 domains found in the response") + return + } + + for _, domain := range s3Domains { + if domainStr, ok := domain.(string); ok { + fmt.Println(domainStr) } } } diff --git a/main.go b/main.go index cb3f67c..a6b7e85 100644 --- a/main.go +++ b/main.go @@ -17,129 +17,116 @@ func (s *stringSliceFlag) Set(value string) error { *s = append(*s, value) return nil } -func main() { - scanUrl := flag.String("scanUrl", "", "URL to be rescanned by jsmonId.") - uploadUrl := flag.String("uploadUrl", "", "URL to upload for scanning") - apiKeyFlag := flag.String("apikey", "", "API key for authentication") - scanFileId := flag.String("scanFile", "", " File to be rescanned by fileId.") - uploadFile := flag.String("uploadFile", "", "File to upload giving path to the file locally.") - getAllResults := flag.String("getAutomationData", "", "Get all automation results") - size := flag.Int("size", 10000, "Number of results to fetch (default 10000)") - fileTypes := flag.String("fileTypes", "", "files type (e.g. pdf,txt)") - getScannerResultsFlag := flag.Bool("getScannerData", false, "Get scanner results") - cron := flag.String("cron", "", "Set cronjob.") - cronNotification := flag.String("notifications", "", "Set cronjob notification channel.") - cronTime := flag.Int64("time", 0, "Set cronjob time.") - cronType := flag.String("vulnerabilitiesType", "", "Set type[URLs, Analysis, Scanner] of cronjob.") - cronDomains := flag.String("domains", "", "Set domains for cronjob.") - cronDomainsNotify := flag.String("domainsNotify", "", "Set notify(true/false) for each domain for cronjob.") - viewurls := flag.Bool("urls", false, "view all urls") - viewurlsSize := flag.Int("urlSize", 10, "Number of URLs to fetch") - scanDomainFlag := flag.String("scanDomain", "", "Domain to automate scan") - wordsFlag := flag.String("words", "", "Comma-separated list of words to include in the scan") - urlswithmultipleResponse := flag.Bool("changedUrls", false, "View changed JS URLs.") - getDomainsFlag := flag.Bool("getDomains", false, "Get all domains for the user.") - var headers stringSliceFlag - flag.Var(&headers, "H", "Custom headers in the format 'Key: Value' (can be used multiple times)") - addCustomWordsFlag := flag.String("addCustomWords", "", "add custom words to the scan") - usageFlag := flag.Bool("usage", false, "View user profile") - viewfiles := flag.Bool("getFiles", false, "view all files") - viewEmails := flag.String("getEmails", "", "Get all emails for specified domains.") - s3domains := flag.String("getS3Domains", "", "get all S3Domains for specified domains") - ips := flag.String("getIps", "", "Get all IPs for specified domains") - gql := flag.String("getGqlOps", "", "Get graph QL operations") - domainUrl := flag.String("getDomainUrls", "", "Get Domain URLs for specified domains") - apiPath := flag.String("getApiPaths", "", "Get the APIs for specified domains") - fileExtensionUrls := flag.String("getFileExtensionUrls", "", "Get URLs containing any file type.") - socialMediaUrls := flag.String("getSocialMediaUrls", "", "Get URLs for social media sites.") - domainStatus := flag.String("getDomainStatus", "", "Get the availabilty of domains") - queryParamsUrls := flag.String("getQueryParamsUrls", "", "Get URLs containing query params for specified domain.") - localhostUrls := flag.String("getLocalhostUrls", "", "Get URLs with localhost in the hostname.") - filteredPortUrls := flag.String("getUrlsWithPorts", "", "Get URLs with port numbers in the hostname") - s3DomainsInvalid := flag.String("getS3DomainsInvalid", "", "Get available S3 domains (404 status).") - compareFlag := flag.String("compare", "", "Compare two js responses by jsmon_ids (format: JSMON_ID1,JSMON_ID2)") - reverseSearchResults := flag.String("reverseSearchResults", "", "Specify the input type (e.g., emails, domainname)") - //getResultByValue := flag.String("value", "", "Specify the input value") - createWordListFlag := flag.String("createWordList", "", "creates a new word list from domains") - searchUrlsByDomainFlag := flag.String("searchUrlsByDomain", "", "Search URLs by domain") - getResultByJsmonId := flag.String("getResultByJsmonId", "", "Get automation results by jsmon ID.") - getResultByFileId := flag.String("getResultByFileId", "", "Get automation results by file ID.") - rescanDomainFlag := flag.String("rescanDomain", "", "Rescan all URLs for a specific domain") - totalAnalysisDataFlag := flag.Bool("totalAnalysisData", false, "total count of overall analysis data") - - flag.Usage = func() { - fmt.Printf("Usage of %s:\n", os.Args[0]) - fmt.Printf(" %s [flags]\n\n", os.Args[0]) - fmt.Println("Flags:") - - // Input section - fmt.Fprintf(os.Stderr, "\nINPUT:\n") - fmt.Fprintf(os.Stderr, " -scanUrl URL to be rescanned by jsmonId.\n") - fmt.Fprintf(os.Stderr, " -uploadUrl URL to upload for scanning.\n") - fmt.Fprintf(os.Stderr, " -scanFile File to be rescanned by fileId.\n") - fmt.Fprintf(os.Stderr, " -uploadFile File to upload (local path)\n") - fmt.Fprintf(os.Stderr, " -scanDomain Domain to automate scan\n") - // Authentication section - fmt.Fprintf(os.Stderr, "\nAUTHENTICATION:\n") - fmt.Fprintf(os.Stderr, " -apikey API key for authentication\n") - - // Output section - fmt.Fprintf(os.Stderr, "\nOUTPUT:\n") - fmt.Fprintf(os.Stderr, " -getAutomationData Get all automation results.\n") - fmt.Fprintf(os.Stderr, " -getScannerData Get scanner results.\n") - fmt.Fprintf(os.Stderr, " -getUrls View all URLs.\n") - fmt.Fprintf(os.Stderr, " -urlSize int Number of URLs to fetch (default 10).\n") - fmt.Fprintf(os.Stderr, " -getFiles View all files.\n") - fmt.Fprintf(os.Stderr, " -fileTypes Specify file types (e.g., pdf,txt), use ',' as separator.\n") - fmt.Fprintf(os.Stderr, " -usage View user profile.\n") - fmt.Fprintf(os.Stderr, " -changedUrls View changed JS URLs.\n") +type Flags struct { + ScanUrl string + UploadUrl string + ApiKey string + ScanFileId string + UploadFile string + GetAllResults string + Size int + FileTypes string + GetScannerResults bool + Cron string + CronNotification string + CronTime int64 + CronType string + CronDomains string + CronDomainsNotify string + ViewUrls bool + ViewUrlsSize int + ScanDomain string + Words string + UrlsWithMultipleResp bool + GetDomains bool + Headers stringSliceFlag + AddCustomWords string + Usage bool + ViewFiles bool + ViewEmails string + S3Domains string + Ips string + Gql string + DomainUrl string + ApiPath string + FileExtensionUrls string + SocialMediaUrls string + DomainStatus string + QueryParamsUrls string + LocalhostUrls string + FilteredPortUrls string + S3DomainsInvalid string + Compare string + ReverseSearchResults string + CreateWordList string + SearchUrlsByDomain string + GetResultByJsmonId string + GetResultByFileId string + RescanDomain string + TotalAnalysisData bool +} - // Cronjob section - // fmt.Fprintf(os.Stderr, "\nCRON JOB:\n") - // fmt.Fprintf(os.Stderr, " -cron Set, update, or stop cronjob\n") - // fmt.Fprintf(os.Stderr, " -notifications Set cronjob notification channel\n") - // fmt.Fprintf(os.Stderr, " -time Set cronjob time\n") - // fmt.Fprintf(os.Stderr, " -vulnerabilitiesType Set type of cronjob (URLs, Analysis, Scanner)\n") - // fmt.Fprintf(os.Stderr, " -domains Set domains for cronjob\n") - // fmt.Fprintf(os.Stderr, " -domainsNotify Set notification for each domain\n") +func parseFlags() *Flags { + f := &Flags{} - // Additional options - fmt.Fprintf(os.Stderr, "\nADDITIONAL OPTIONS:\n") - fmt.Fprintf(os.Stderr, " -H Custom headers (can be used multiple times).\n") - fmt.Fprintf(os.Stderr, " -words Comma-separated list of words to include in the scan.\n") - fmt.Fprintf(os.Stderr, " -getDomains Get all domains for the user.\n") - fmt.Fprintf(os.Stderr, " -getEmails Get all emails for specified domains.\n") - fmt.Fprintf(os.Stderr, " -getS3Domains Get all S3 domains for specified domains.\n") - fmt.Fprintf(os.Stderr, " -getIps Get all IPs for specified domains.\n") - fmt.Fprintf(os.Stderr, " -getDomainUrls Get domain URLs for specified domains.\n") - fmt.Fprintf(os.Stderr, " -getApiPaths Get API paths for specified domains.\n") - fmt.Fprintf(os.Stderr, " -getFileExtensionUrls Get URLs containing any file type.\n") - fmt.Fprintf(os.Stderr, " -getSocialMediaUrls Get URLs for social media sites.\n") - fmt.Fprintf(os.Stderr, " -getDomainStatus Get availability status of domains.\n") - fmt.Fprintf(os.Stderr, " -getQueryParamsUrls Get URLs containing query params for specified domain.\n") - fmt.Fprintf(os.Stderr, " -getLocalhostUrls Get URLs with localhost in the hostname.\n") - fmt.Fprintf(os.Stderr, " -getUrlsWithPorts Get URLs with port numbers in the hostname.\n") - fmt.Fprintf(os.Stderr, " -getS3DomainsInvalid Get available S3 domains (404 status).\n") - fmt.Fprintf(os.Stderr, " -rescanDomain Rescan all URLs for a specific domain.\n") - fmt.Fprintf(os.Stderr, " -searchUrlsByDomain Search URLs by domain.\n") - fmt.Fprintf(os.Stderr, " -compare Compare two JS responses by IDs (format: ID1,ID2).\n") - fmt.Fprintf(os.Stderr, " -getGqlOps Get GraphQL operations for specified domains.\n") - fmt.Fprintf(os.Stderr, " -totalAnalysisData Get total count of overall analysis data.\n") - fmt.Fprintf(os.Stderr, " -getResultByJsmonId Get automation results by jsmon ID.\n") - fmt.Fprintf(os.Stderr, " -getResultByFileId Get automation results by file ID.\n") + flag.StringVar(&f.ScanUrl, "scanUrl", "", "URL to be rescanned by jsmonId.") + flag.StringVar(&f.UploadUrl, "uploadUrl", "", "URL to upload for scanning") + flag.StringVar(&f.ApiKey, "apikey", "", "API key for authentication") + flag.StringVar(&f.ScanFileId, "scanFile", "", "File to be rescanned by fileId.") + flag.StringVar(&f.UploadFile, "uploadFile", "", "File to upload giving path to the file locally.") + flag.StringVar(&f.GetAllResults, "getAutomationData", "", "Get all automation results") + flag.IntVar(&f.Size, "size", 10000, "Number of results to fetch (default 10000)") + flag.StringVar(&f.FileTypes, "fileTypes", "", "files type (e.g. pdf,txt)") + flag.BoolVar(&f.GetScannerResults, "getScannerData", false, "Get scanner results") + flag.StringVar(&f.Cron, "cron", "", "Set cronjob.") + flag.StringVar(&f.CronNotification, "notifications", "", "Set cronjob notification channel.") + flag.Int64Var(&f.CronTime, "time", 0, "Set cronjob time.") + flag.StringVar(&f.CronType, "vulnerabilitiesType", "", "Set type[URLs, Analysis, Scanner] of cronjob.") + flag.StringVar(&f.CronDomains, "domains", "", "Set domains for cronjob.") + flag.StringVar(&f.CronDomainsNotify, "domainsNotify", "", "Set notify(true/false) for each domain for cronjob.") + flag.BoolVar(&f.ViewUrls, "urls", false, "view all urls") + flag.IntVar(&f.ViewUrlsSize, "urlSize", 10, "Number of URLs to fetch") + flag.StringVar(&f.ScanDomain, "scanDomain", "", "Domain to automate scan") + flag.StringVar(&f.Words, "words", "", "Comma-separated list of words to include in the scan") + flag.BoolVar(&f.UrlsWithMultipleResp, "changedUrls", false, "View changed JS URLs.") + flag.BoolVar(&f.GetDomains, "getDomains", false, "Get all domains for the user.") + flag.Var(&f.Headers, "H", "Custom headers in the format 'Key: Value' (can be used multiple times)") + flag.StringVar(&f.AddCustomWords, "addCustomWords", "", "add custom words to the scan") + flag.BoolVar(&f.Usage, "usage", false, "View user profile") + flag.BoolVar(&f.ViewFiles, "getFiles", false, "view all files") + flag.StringVar(&f.ViewEmails, "getEmails", "", "Get all emails for specified domains.") + flag.StringVar(&f.S3Domains, "getS3Domains", "", "get all S3Domains for specified domains") + flag.StringVar(&f.Ips, "getIps", "", "Get all IPs for specified domains") + flag.StringVar(&f.Gql, "getGqlOps", "", "Get graph QL operations") + flag.StringVar(&f.DomainUrl, "getDomainUrls", "", "Get Domain URLs for specified domains") + flag.StringVar(&f.ApiPath, "getApiPaths", "", "Get the APIs for specified domains") + flag.StringVar(&f.FileExtensionUrls, "getFileExtensionUrls", "", "Get URLs containing any file type.") + flag.StringVar(&f.SocialMediaUrls, "getSocialMediaUrls", "", "Get URLs for social media sites.") + flag.StringVar(&f.DomainStatus, "getDomainStatus", "", "Get the availabilty of domains") + flag.StringVar(&f.QueryParamsUrls, "getQueryParamsUrls", "", "Get URLs containing query params for specified domain.") + flag.StringVar(&f.LocalhostUrls, "getLocalhostUrls", "", "Get URLs with localhost in the hostname.") + flag.StringVar(&f.FilteredPortUrls, "getUrlsWithPorts", "", "Get URLs with port numbers in the hostname") + flag.StringVar(&f.S3DomainsInvalid, "getS3DomainsInvalid", "", "Get available S3 domains (404 status).") + flag.StringVar(&f.Compare, "compare", "", "Compare two js responses by jsmon_ids (format: JSMON_ID1,JSMON_ID2)") + flag.StringVar(&f.ReverseSearchResults, "reverseSearchResults", "", "Specify the input type (e.g., emails, domainname)") + flag.StringVar(&f.CreateWordList, "createWordList", "", "creates a new word list from domains") + flag.StringVar(&f.SearchUrlsByDomain, "searchUrlsByDomain", "", "Search URLs by domain") + flag.StringVar(&f.GetResultByJsmonId, "getResultByJsmonId", "", "Get automation results by jsmon ID.") + flag.StringVar(&f.GetResultByFileId, "getResultByFileId", "", "Get automation results by file ID.") + flag.StringVar(&f.RescanDomain, "rescanDomain", "", "Rescan all URLs for a specific domain") + flag.BoolVar(&f.TotalAnalysisData, "totalAnalysisData", false, "total count of overall analysis data") - // Automation results section - fmt.Fprintf(os.Stderr, "\nAUTOMATION RESULTS BY FIELD:\n") - fmt.Fprintf(os.Stderr, " -reverseSearchResults =\n") - fmt.Fprintf(os.Stderr, " Search by field : emails, domainname, extracteddomains, s3domains, url, extractedurls, ipv4addresses, ipv6addresses, jwttokens, gqlquery, gqlmutation, guids, apipaths, vulnerabilities, nodemodules, domainstatus, queryparamsurls, socialmediaurls, filterdporturls, gqlfragment, s3domainsinvalid, fileextensionurls, localhosturls.\n") + flag.Parse() - } + return f +} - flag.Parse() +func main() { + flags := parseFlags() - if *apiKeyFlag != "" { - setAPIKey(*apiKeyFlag) + if flags.ApiKey != "" { + setAPIKey(flags.ApiKey) } else { err := loadAPIKey() if err != nil { @@ -149,170 +136,137 @@ func main() { } } - if flag.NFlag() == 0 || (flag.NFlag() == 1 && *apiKeyFlag != "") { + if flag.NFlag() == 0 || (flag.NFlag() == 1 && flags.ApiKey != "") { fmt.Println("No action specified. Use -h or --help for usage information.") flag.Usage() os.Exit(1) } + err := executeCommand(flags) + if err != nil { + fmt.Printf("Error executing command: %v\n", err) + os.Exit(1) + } +} + +func executeCommand(flags *Flags) error { switch { - case *scanFileId != "": - scanFileEndpoint(*scanFileId) - case *uploadFile != "": - uploadFileEndpoint(*uploadFile, headers) - case *viewurls: - viewUrls(*viewurlsSize) - case *viewfiles: - viewFiles() - case *uploadUrl != "": - uploadUrlEndpoint(*uploadUrl, headers) - case *rescanDomainFlag != "": - rescanDomain(*rescanDomainFlag) - case *totalAnalysisDataFlag: - totalAnalysisData() - case *searchUrlsByDomainFlag != "": - searchUrlsByDomain(*searchUrlsByDomainFlag) - case *urlswithmultipleResponse: - urlsmultipleResponse() - case *viewEmails != "": - domains := strings.Split(*viewEmails, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getEmails(domains) - case *getResultByJsmonId != "": - getAutomationResultsByJsmonId(strings.TrimSpace(*getResultByJsmonId)) - case *reverseSearchResults != "": - parts := strings.SplitN(*reverseSearchResults, "=", 2) - if len(parts) != 2 { - fmt.Println("Invalid format for reverseSearchResults. Use field=value format.") - return - } + case flags.ScanFileId != "": + return scanFileEndpoint(flags.ScanFileId) + case flags.UploadFile != "": + return uploadFileEndpoint(flags.UploadFile, flags.Headers) + case flags.ViewUrls: + return viewUrls(flags.ViewUrlsSize) + case flags.ViewFiles: + return viewFiles() + case flags.UploadUrl != "": + return uploadUrlEndpoint(flags.UploadUrl, flags.Headers) + case flags.RescanDomain != "": + return rescanDomain(flags.RescanDomain) + case flags.TotalAnalysisData: + return totalAnalysisData() + case flags.SearchUrlsByDomain != "": + return searchUrlsByDomain(flags.SearchUrlsByDomain) + case flags.UrlsWithMultipleResp: + return urlsmultipleResponse() + case flags.ViewEmails != "": + domains := splitAndTrim(flags.ViewEmails) + return getEmails(domains) + case flags.GetResultByJsmonId != "": + return getAutomationResultsByJsmonId(strings.TrimSpace(flags.GetResultByJsmonId)) + case flags.ReverseSearchResults != "": + return handleReverseSearchResults(flags.ReverseSearchResults) + case flags.GetResultByFileId != "": + return getAutomationResultsByFileId(strings.TrimSpace(flags.GetResultByFileId)) + case flags.S3Domains != "": + domains := splitAndTrim(flags.S3Domains) + return getS3Domains(domains) + case flags.Ips != "": + domains := splitAndTrim(flags.Ips) + return getAllIps(domains) + case flags.Gql != "": + domains := splitAndTrim(flags.Gql) + return getGqlOps(domains) + case flags.DomainUrl != "": + domains := splitAndTrim(flags.DomainUrl) + return getDomainUrls(domains) + case flags.ApiPath != "": + domains := splitAndTrim(flags.ApiPath) + return getApiPaths(domains) + case flags.GetScannerResults: + return getScannerResults() + case flags.ScanUrl != "": + return rescanUrlEndpoint(flags.ScanUrl) + case flags.Cron == "start": + return StartCron(flags.CronNotification, flags.CronTime, flags.CronType, flags.CronDomains, flags.CronDomainsNotify) + case flags.Cron == "stop": + return StopCron() + case flags.GetDomains: + return getDomains() + case flags.FileExtensionUrls != "": + extensions := splitAndTrim(flags.FileTypes) + return getAllFileExtensionUrls(flags.FileExtensionUrls, extensions, flags.Size) + case flags.DomainStatus != "": + return getAllDomainsStatus(flags.DomainStatus, flags.Size) + case flags.SocialMediaUrls != "": + return getAllSocialMediaUrls(flags.SocialMediaUrls, flags.Size) + case flags.QueryParamsUrls != "": + return getAllQueryParamsUrls(flags.QueryParamsUrls, flags.Size) + case flags.LocalhostUrls != "": + return getAllLocalhostUrls(flags.LocalhostUrls, flags.Size) + case flags.FilteredPortUrls != "": + return getAllFilteredPortUrls(flags.FilteredPortUrls, flags.Size) + case flags.S3DomainsInvalid != "": + return getAllS3DomainsInvalid(flags.S3DomainsInvalid, flags.Size) + case flags.Compare != "": + return handleCompare(flags.Compare) + case flags.Cron == "update": + return UpdateCron(flags.CronNotification, flags.CronType, flags.CronDomains, flags.CronDomainsNotify, flags.CronTime) + case flags.GetAllResults != "": + return getAllAutomationResults(flags.GetAllResults, flags.Size) + case flags.ScanDomain != "": + words := splitAndTrim(flags.Words) + fmt.Printf("Domain: %s, Words: %v\n", flags.ScanDomain, words) + return automateScanDomain(flags.ScanDomain, words) + case flags.Usage: + return callViewProfile() + case flags.CreateWordList != "": + domains := splitAndTrim(flags.CreateWordList) + return createWordList(domains) + case flags.AddCustomWords != "": + words := splitAndTrim(flags.AddCustomWords) + return addCustomWordUser(words) + default: + return fmt.Errorf("no valid action specified") + } +} - field := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) +func splitAndTrim(s string) []string { + parts := strings.Split(s, ",") + for i, part := range parts { + parts[i] = strings.TrimSpace(part) + } + return parts +} - getAutomationResultsByInput(field, value) +func handleReverseSearchResults(input string) error { + parts := strings.SplitN(input, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("invalid format for reverseSearchResults. Use field=value format") + } - case *getResultByFileId != "": - getAutomationResultsByFileId(strings.TrimSpace(*getResultByFileId)) - case *s3domains != "": - domains := strings.Split(*s3domains, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getS3Domains(domains) - case *ips != "": - domains := strings.Split(*ips, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getAllIps(domains) - case *gql != "": - domains := strings.Split(*gql, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getGqlOps(domains) - case *domainUrl != "": - domains := strings.Split(*domainUrl, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getDomainUrls(domains) - case *apiPath != "": - domains := strings.Split(*apiPath, ",") - for i, domain := range domains { - domains[i] = strings.TrimSpace(domain) - } - getApiPaths(domains) - case *getScannerResultsFlag: - getScannerResults() - case *scanUrl != "": - rescanUrlEndpoint(*scanUrl) - case *cron == "start": - StartCron(*cronNotification, *cronTime, *cronType, *cronDomains, *cronDomainsNotify) - case *cron == "stop": - StopCron() - case *getDomainsFlag: - getDomains() + field := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) - case *fileExtensionUrls != "": - extensions := strings.Split(*fileTypes, ",") - for i, extension := range extensions { - extensions[i] = strings.TrimSpace(extension) - } - getAllFileExtensionUrls(*fileExtensionUrls, extensions, *size) - case *domainStatus != "": - // domains := strings.Split(*domainStatus, ",") - // for i, domain := range domains { - // domains[i] = strings.TrimSpace(domain) - // } - getAllDomainsStatus(*domainStatus, *size) + return getAutomationResultsByInput(field, value) +} - case *socialMediaUrls != "": - getAllSocialMediaUrls(*socialMediaUrls, *size) - case *queryParamsUrls != "": - getAllQueryParamsUrls(*queryParamsUrls, *size) - case *localhostUrls != "": - getAllLocalhostUrls(*localhostUrls, *size) - case *filteredPortUrls != "": - getAllFilteredPortUrls(*filteredPortUrls, *size) - case *s3DomainsInvalid != "": - getAllS3DomainsInvalid(*s3DomainsInvalid, *size) - case *compareFlag != "": - ids := strings.Split(*compareFlag, ",") - if len(ids) != 2 { - fmt.Println("Invalid format for compare. Use: JSMON_ID1,JSMON_ID2") - os.Exit(1) - } - compareEndpoint(strings.TrimSpace(ids[0]), strings.TrimSpace(ids[1])) - case *cron == "update": - UpdateCron(*cronNotification, *cronType, *cronDomains, *cronDomainsNotify, *cronTime) - case *getAllResults != "": - getAllAutomationResults(*getAllResults, *size) - case *scanDomainFlag != "": - words := []string{} - if *wordsFlag != "" { - words = strings.Split(*wordsFlag, ",") - } - fmt.Printf("Domain: %s, Words: %v\n", *scanDomainFlag, words) - automateScanDomain(*scanDomainFlag, words) - case *usageFlag: - callViewProfile() - case *createWordListFlag != "": - domains := strings.Split(*createWordListFlag, ",") - createWordList(domains) - case *addCustomWordsFlag != "": - words := strings.Split(*addCustomWordsFlag, ",") - addCustomWordUser(words) - default: - fmt.Println("No valid action specified.") - flag.Usage() - os.Exit(1) +func handleCompare(input string) error { + ids := strings.Split(input, ",") + if len(ids) != 2 { + return fmt.Errorf("invalid format for compare. Use: JSMON_ID1,JSMON_ID2") } + return compareEndpoint(strings.TrimSpace(ids[0]), strings.TrimSpace(ids[1])) } -// type Args struct { -// Cron string -// CronNotification string -// CronTime int64 -// CronType string -// } - -// func parseArgs() Args { -// //CRON JOB FLAGS -> -// cron := flag.String("cron", "", "Set cronjob.") -// cronNotification := flag.String("notifications", "", "Set cronjob notification.") -// cronTime := flag.Int64("time", 0, "Set cronjob time.") -// cronType := flag.String("type", "", "Set type of cronjob.") - -// flag.Parse() - -// return Args{ -// Cron: *cron, -// CronNotification: *cronNotification, -// CronTime: *cronTime, -// CronType: *cronType, -// } -// } +// ... (rest of the code remains the same) diff --git a/viewFiles.go b/viewFiles.go index d275ea3..a078333 100644 --- a/viewFiles.go +++ b/viewFiles.go @@ -3,9 +3,10 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" + "time" ) type FileResponse struct { @@ -14,48 +15,53 @@ type FileResponse struct { } type FileItem struct { - FileID string `json:"fileId"` - FileSize float64 `json:"fileSize"` - FileName string `json:"fileName"` - FileKey string `json:"fileKey"` - Urls int `json:"urls"` - CreatedAt string `json:"createdAt"` + FileID string `json:"fileId"` + FileSize float64 `json:"fileSize"` + FileName string `json:"fileName"` + FileKey string `json:"fileKey"` + Urls int `json:"urls"` + CreatedAt time.Time `json:"createdAt"` } func viewFiles() { endpoint := fmt.Sprintf("%s/viewFiles", apiBaseURL) - client := &http.Client{} - req, err := http.NewRequest("GET", endpoint, nil) + + req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { - fmt.Println("Error creating request:", err) + fmt.Printf("Error creating request: %v\n", err) return } req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { - fmt.Printf("Failed to send request: %v", err) + fmt.Printf("Failed to send request: %v\n", err) return } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + fmt.Printf("Unexpected status code: %d\n", resp.StatusCode) + return + } + + body, err := io.ReadAll(resp.Body) if err != nil { - fmt.Printf("Failed to read response body: %v", err) + fmt.Printf("Failed to read response body: %v\n", err) return } var response FileResponse - err = json.Unmarshal(body, &response) - if err != nil { - fmt.Printf("Failed to unmarshal JSON response: %v", err) + if err := json.Unmarshal(body, &response); err != nil { + fmt.Printf("Failed to unmarshal JSON response: %v\n", err) return } fmt.Println(response.Message) for _, fileItem := range response.Data { fmt.Printf("File Name: %s\nFile Size: %.3f MB\nFile ID: %s\nFile Key: %s\nNumber of URLs: %d\nCreated At: %s\n\n", - fileItem.FileName, fileItem.FileSize, fileItem.FileID, fileItem.FileKey, fileItem.Urls, fileItem.CreatedAt) + fileItem.FileName, fileItem.FileSize, fileItem.FileID, fileItem.FileKey, fileItem.Urls, fileItem.CreatedAt.Format(time.RFC3339)) } } diff --git a/viewUrls.go b/viewUrls.go index 97bb7d2..b2750d2 100644 --- a/viewUrls.go +++ b/viewUrls.go @@ -1,11 +1,13 @@ package main import ( + "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" + "time" ) type URLResponse struct { @@ -18,32 +20,36 @@ type URLItem struct { } func viewUrls(size int) { - endpoint := fmt.Sprintf("%s/searchAllUrls?size=%d&start=0", apiBaseURL, size) // Use the size parameter - client := &http.Client{} - req, err := http.NewRequest("GET", endpoint, nil) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + endpoint := fmt.Sprintf("%s/searchAllUrls?size=%d&start=0", apiBaseURL, size) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) if err != nil { - fmt.Println("Error creating request:", err) + fmt.Printf("Error creating request: %v\n", err) return } req.Header.Set("X-Jsmon-Key", strings.TrimSpace(getAPIKey())) + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { - fmt.Printf("failed to send request: %v", err) + fmt.Printf("Failed to send request: %v\n", err) return } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - fmt.Printf("failed to read response body: %v", err) + if resp.StatusCode != http.StatusOK { + fmt.Printf("Unexpected status code: %d\n", resp.StatusCode) return } + var response URLResponse - err = json.Unmarshal(body, &response) + err = json.NewDecoder(resp.Body).Decode(&response) if err != nil { - fmt.Printf("failed to unmarshal JSON response: %v", err) + fmt.Printf("Failed to decode JSON response: %v\n", err) return }