2022-09-19 01:13:59 +05:30
|
|
|
package nucleicloud
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
2022-12-04 20:43:19 +05:30
|
|
|
"encoding/json"
|
2022-09-19 01:13:59 +05:30
|
|
|
"fmt"
|
2022-09-19 08:38:52 +02:00
|
|
|
"io"
|
2022-12-06 14:11:32 +05:30
|
|
|
"mime/multipart"
|
2022-09-19 01:13:59 +05:30
|
|
|
"net/http"
|
2022-11-24 14:00:22 +05:30
|
|
|
"net/url"
|
2022-12-06 14:11:32 +05:30
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
2022-09-19 01:13:59 +05:30
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
jsoniter "github.com/json-iterator/go"
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
|
|
|
|
"github.com/projectdiscovery/retryablehttp-go"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Client is a client for result retrieval from nuclei-cloud API
|
|
|
|
|
type Client struct {
|
|
|
|
|
baseURL string
|
|
|
|
|
apiKey string
|
|
|
|
|
httpclient *retryablehttp.Client
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
2022-12-04 20:43:19 +05:30
|
|
|
pollInterval = 3 * time.Second
|
2022-10-22 04:06:52 +05:30
|
|
|
resultSize = 100
|
2022-12-04 20:43:19 +05:30
|
|
|
defaultBaseURL = "https://cloud-dev.nuclei.sh"
|
2022-09-19 01:13:59 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// New returns a nuclei-cloud API client
|
|
|
|
|
func New(baseURL, apiKey string) *Client {
|
|
|
|
|
options := retryablehttp.DefaultOptionsSingle
|
2022-12-04 20:43:19 +05:30
|
|
|
options.NoAdjustTimeout = true
|
|
|
|
|
options.Timeout = 60 * time.Second
|
2022-09-19 01:13:59 +05:30
|
|
|
client := retryablehttp.NewClient(options)
|
|
|
|
|
|
|
|
|
|
baseAppURL := baseURL
|
|
|
|
|
if baseAppURL == "" {
|
|
|
|
|
baseAppURL = defaultBaseURL
|
|
|
|
|
}
|
|
|
|
|
return &Client{httpclient: client, baseURL: baseAppURL, apiKey: apiKey}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddScan adds a scan for templates and target to nuclei server
|
|
|
|
|
func (c *Client) AddScan(req *AddScanRequest) (string, error) {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := jsoniter.NewEncoder(&buf).Encode(req); err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", errors.Wrap(err, "could not encode request")
|
2022-09-19 01:13:59 +05:30
|
|
|
}
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/scan", c.baseURL), bytes.NewReader(buf.Bytes()))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-09-19 01:13:59 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", errors.Wrap(err, "could not do request")
|
2022-09-19 01:13:59 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
2022-09-19 01:13:59 +05:30
|
|
|
var data map[string]string
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&data); err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not decode resp")
|
|
|
|
|
}
|
|
|
|
|
id := data["id"]
|
|
|
|
|
return id, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetResults gets results from nuclei server for an ID
|
|
|
|
|
// until there are no more results left to retrieve.
|
2022-11-24 14:00:22 +05:30
|
|
|
func (c *Client) GetResults(ID string, callback func(*output.ResultEvent), checkProgress bool, limit int) error {
|
2022-09-19 01:13:59 +05:30
|
|
|
lastID := int64(0)
|
2022-11-24 14:00:22 +05:30
|
|
|
|
2022-09-19 01:13:59 +05:30
|
|
|
for {
|
2022-11-24 14:00:22 +05:30
|
|
|
uri := fmt.Sprintf("%s/results?id=%s&from=%d&size=%d", c.baseURL, ID, lastID, limit)
|
2022-10-22 04:06:52 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, uri, nil)
|
2022-09-19 01:13:59 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-09-19 01:13:59 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return errors.Wrap(err, "could not do request")
|
2022-09-19 01:13:59 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
|
2022-09-19 01:13:59 +05:30
|
|
|
var items GetResultsResponse
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&items); err != nil {
|
|
|
|
|
resp.Body.Close()
|
|
|
|
|
return errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
for _, item := range items.Items {
|
|
|
|
|
lastID = item.ID
|
|
|
|
|
|
|
|
|
|
var result output.ResultEvent
|
|
|
|
|
if err := jsoniter.NewDecoder(strings.NewReader(item.Raw)).Decode(&result); err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not decode result item")
|
|
|
|
|
}
|
|
|
|
|
callback(&result)
|
|
|
|
|
}
|
2022-10-22 04:06:52 +05:30
|
|
|
|
|
|
|
|
//This is checked during scan is added else if no item found break out of loop.
|
|
|
|
|
if checkProgress {
|
|
|
|
|
if items.Finished && len(items.Items) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
} else if len(items.Items) == 0 {
|
2022-09-19 01:13:59 +05:30
|
|
|
break
|
|
|
|
|
}
|
2022-10-22 04:06:52 +05:30
|
|
|
|
2022-09-19 01:13:59 +05:30
|
|
|
time.Sleep(pollInterval)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2022-10-22 04:06:52 +05:30
|
|
|
|
2022-11-24 14:00:22 +05:30
|
|
|
func (c *Client) GetScans(limit int, from string) ([]GetScanRequest, error) {
|
2022-10-22 04:06:52 +05:30
|
|
|
var items []GetScanRequest
|
2022-11-24 14:00:22 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, fmt.Sprintf("%s/scan?from=%s&size=%d", c.baseURL, url.QueryEscape(from), limit), nil)
|
2022-10-22 04:06:52 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-10-22 04:06:52 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return nil, errors.Wrap(err, "could not do request")
|
2022-10-22 04:06:52 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
2022-10-22 04:06:52 +05:30
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&items); err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
return items, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 01:37:00 +05:30
|
|
|
// Delete a scan and it's issues by the scan id.
|
2022-10-22 04:06:52 +05:30
|
|
|
func (c *Client) DeleteScan(id string) (DeleteScanResults, error) {
|
|
|
|
|
deletescan := DeleteScanResults{}
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodDelete, fmt.Sprintf("%s/scan?id=%s", c.baseURL, id), nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return deletescan, errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-10-22 04:06:52 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return deletescan, errors.Wrap(err, "could not do request")
|
2022-10-22 04:06:52 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
2022-10-22 04:06:52 +05:30
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&deletescan); err != nil {
|
|
|
|
|
return deletescan, errors.Wrap(err, "could not delete scan")
|
|
|
|
|
}
|
|
|
|
|
return deletescan, nil
|
|
|
|
|
}
|
2022-11-15 01:37:00 +05:30
|
|
|
|
|
|
|
|
// StatusDataSource returns the status for a data source
|
|
|
|
|
func (c *Client) StatusDataSource(statusRequest StatusDataSourceRequest) (string, error) {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := jsoniter.NewEncoder(&buf).Encode(statusRequest); err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", errors.Wrap(err, "could not encode request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/datasources/status", c.baseURL), bytes.NewReader(buf.Bytes()))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", errors.Wrap(err, "could not do request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
2022-11-15 01:37:00 +05:30
|
|
|
|
|
|
|
|
var data map[string]interface{}
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&data); err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not decode resp")
|
|
|
|
|
}
|
|
|
|
|
id := data["id"].(string)
|
|
|
|
|
return id, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddDataSource adds a new data source
|
2022-11-16 13:38:55 +05:30
|
|
|
func (c *Client) AddDataSource(req AddDataSourceRequest) (string, string, error) {
|
2022-11-15 01:37:00 +05:30
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := jsoniter.NewEncoder(&buf).Encode(req); err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", "", errors.Wrap(err, "could not encode request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/datasources", c.baseURL), bytes.NewReader(buf.Bytes()))
|
|
|
|
|
if err != nil {
|
2022-11-16 13:38:55 +05:30
|
|
|
return "", "", errors.Wrap(err, "could not make request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return "", "", errors.Wrap(err, "could not do request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
2022-11-15 01:37:00 +05:30
|
|
|
|
|
|
|
|
var data map[string]interface{}
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&data); err != nil {
|
2022-11-16 13:38:55 +05:30
|
|
|
return "", "", errors.Wrap(err, "could not decode resp")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
|
|
|
|
id := data["id"].(string)
|
2022-11-16 13:38:55 +05:30
|
|
|
secret, _ := data["secret"].(string)
|
|
|
|
|
return id, secret, nil
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SyncDataSource syncs contents for a data source. The call blocks until
|
|
|
|
|
// update is completed.
|
|
|
|
|
func (c *Client) SyncDataSource(ID string) error {
|
2022-12-04 20:43:19 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, fmt.Sprintf("%s/datasources/%s/sync", c.baseURL, ID), nil)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return errors.Wrap(err, "could not do request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
defer resp.Body.Close()
|
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
2022-11-15 01:37:00 +05:30
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ExistsDataSourceItem identifies whether data source item exist
|
|
|
|
|
func (c *Client) ExistsDataSourceItem(req ExistsDataSourceItemRequest) error {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := jsoniter.NewEncoder(&buf).Encode(req); err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return errors.Wrap(err, "could not encode request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/datasources/exists", c.baseURL), bytes.NewReader(buf.Bytes()))
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2022-11-15 01:37:00 +05:30
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
func (c *Client) ListDatasources() ([]GetDataSourceResponse, error) {
|
|
|
|
|
var items []GetDataSourceResponse
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, fmt.Sprintf("%s/datasources", c.baseURL), nil)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return items, errors.Wrap(err, "could not make request")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
2022-11-15 01:37:00 +05:30
|
|
|
if err != nil {
|
2022-12-04 20:43:19 +05:30
|
|
|
return nil, errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&items); err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not decode results")
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
return items, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 14:11:32 +05:30
|
|
|
func (c *Client) ListTargets(query string) ([]GetTargetResponse, error) {
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
_, _ = builder.WriteString(c.baseURL)
|
|
|
|
|
_, _ = builder.WriteString("/targets")
|
|
|
|
|
if query != "" {
|
|
|
|
|
_, _ = builder.WriteString("?query=")
|
2022-12-07 00:23:32 +05:30
|
|
|
_, _ = builder.WriteString(url.QueryEscape(query))
|
2022-12-06 14:11:32 +05:30
|
|
|
}
|
|
|
|
|
|
2022-12-04 21:48:05 +05:30
|
|
|
var items []GetTargetResponse
|
2022-12-06 14:11:32 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, builder.String(), nil)
|
2022-12-04 21:48:05 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&items); err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
return items, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 14:11:32 +05:30
|
|
|
func (c *Client) ListTemplates(query string) ([]GetTemplatesResponse, error) {
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
_, _ = builder.WriteString(c.baseURL)
|
|
|
|
|
_, _ = builder.WriteString("/templates")
|
|
|
|
|
if query != "" {
|
|
|
|
|
_, _ = builder.WriteString("?query=")
|
2022-12-07 00:23:32 +05:30
|
|
|
_, _ = builder.WriteString(url.QueryEscape(query))
|
2022-12-06 14:11:32 +05:30
|
|
|
}
|
|
|
|
|
|
2022-12-04 21:48:05 +05:30
|
|
|
var items []GetTemplatesResponse
|
2022-12-06 14:12:45 +05:30
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodGet, builder.String(), nil)
|
2022-12-04 21:48:05 +05:30
|
|
|
if err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&items); err != nil {
|
|
|
|
|
return items, errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
return items, nil
|
|
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
|
2022-12-05 23:02:18 +05:30
|
|
|
func (c *Client) RemoveDatasource(datasource string) error {
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodDelete, fmt.Sprintf("%s/datasources/%s", c.baseURL, datasource), nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 14:11:32 +05:30
|
|
|
func (c *Client) AddTemplate(name, contents string) (string, error) {
|
|
|
|
|
file, err := os.Open(contents)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not open contents")
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
writer := multipart.NewWriter(&buf)
|
|
|
|
|
_ = writer.WriteField("name", name)
|
|
|
|
|
fileWriter, _ := writer.CreateFormFile("file", filepath.Base(contents))
|
|
|
|
|
_, _ = io.Copy(fileWriter, file)
|
|
|
|
|
_ = writer.Close()
|
|
|
|
|
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/templates", c.baseURL), &buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
httpReq.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
var item AddItemResponse
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&item); err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
return item.Ok, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) AddTarget(name, contents string) (string, error) {
|
|
|
|
|
file, err := os.Open(contents)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not open contents")
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
writer := multipart.NewWriter(&buf)
|
|
|
|
|
_ = writer.WriteField("name", name)
|
|
|
|
|
fileWriter, _ := writer.CreateFormFile("file", filepath.Base(contents))
|
|
|
|
|
_, _ = io.Copy(fileWriter, file)
|
|
|
|
|
_ = writer.Close()
|
|
|
|
|
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodPost, fmt.Sprintf("%s/targets", c.baseURL), &buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
httpReq.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
var item AddItemResponse
|
|
|
|
|
if err := jsoniter.NewDecoder(resp.Body).Decode(&item); err != nil {
|
|
|
|
|
return "", errors.Wrap(err, "could not decode results")
|
|
|
|
|
}
|
|
|
|
|
return item.Ok, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) RemoveTemplate(ID int64) error {
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodDelete, fmt.Sprintf("%s/templates/%d", c.baseURL, ID), nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) RemoveTarget(ID int64) error {
|
|
|
|
|
httpReq, err := retryablehttp.NewRequest(http.MethodDelete, fmt.Sprintf("%s/targets/%d", c.baseURL, ID), nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not make request")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := c.sendRequest(httpReq)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-04 20:43:19 +05:30
|
|
|
const apiKeyParameter = "X-API-Key"
|
|
|
|
|
|
|
|
|
|
type errorResponse struct {
|
|
|
|
|
Message string `json:"message"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *Client) sendRequest(req *retryablehttp.Request) (*http.Response, error) {
|
|
|
|
|
req.Header.Set(apiKeyParameter, c.apiKey)
|
|
|
|
|
|
|
|
|
|
resp, err := c.httpclient.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.Wrap(err, "could not do request")
|
|
|
|
|
}
|
|
|
|
|
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest {
|
2022-11-15 01:37:00 +05:30
|
|
|
data, _ := io.ReadAll(resp.Body)
|
|
|
|
|
resp.Body.Close()
|
2022-12-04 20:43:19 +05:30
|
|
|
var errRes errorResponse
|
|
|
|
|
if err = json.NewDecoder(bytes.NewReader(data)).Decode(&errRes); err == nil {
|
|
|
|
|
return nil, errors.New(errRes.Message)
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("unknown error, status code: %d=%s", resp.StatusCode, string(data))
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|
2022-12-04 20:43:19 +05:30
|
|
|
return resp, nil
|
2022-11-15 01:37:00 +05:30
|
|
|
}
|