github.com/crowdsecurity/crowdsec@v1.6.1/pkg/apiclient/client.go (about)

     1  package apiclient
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"fmt"
     8  	"net"
     9  	"net/http"
    10  	"net/url"
    11  	"strings"
    12  
    13  	"github.com/golang-jwt/jwt/v4"
    14  
    15  	"github.com/crowdsecurity/crowdsec/pkg/models"
    16  )
    17  
    18  var (
    19  	InsecureSkipVerify = false
    20  	Cert               *tls.Certificate
    21  	CaCertPool         *x509.CertPool
    22  )
    23  
    24  type ApiClient struct {
    25  	/*The http client used to make requests*/
    26  	client *http.Client
    27  	/*Reuse a single struct instead of allocating one for each service on the heap.*/
    28  	common service
    29  	/*config stuff*/
    30  	BaseURL   *url.URL
    31  	PapiURL   *url.URL
    32  	URLPrefix string
    33  	UserAgent string
    34  	/*exposed Services*/
    35  	Decisions      *DecisionsService
    36  	DecisionDelete *DecisionDeleteService
    37  	Alerts         *AlertsService
    38  	Auth           *AuthService
    39  	Metrics        *MetricsService
    40  	Signal         *SignalService
    41  	HeartBeat      *HeartBeatService
    42  }
    43  
    44  func (a *ApiClient) GetClient() *http.Client {
    45  	return a.client
    46  }
    47  
    48  func (a *ApiClient) IsEnrolled() bool {
    49  	jwtTransport := a.client.Transport.(*JWTTransport)
    50  	tokenStr := jwtTransport.Token
    51  
    52  	token, _ := jwt.Parse(tokenStr, nil)
    53  	if token == nil {
    54  		return false
    55  	}
    56  
    57  	claims := token.Claims.(jwt.MapClaims)
    58  	_, ok := claims["organization_id"]
    59  
    60  	return ok
    61  }
    62  
    63  type service struct {
    64  	client *ApiClient
    65  }
    66  
    67  func NewClient(config *Config) (*ApiClient, error) {
    68  	t := &JWTTransport{
    69  		MachineID:      &config.MachineID,
    70  		Password:       &config.Password,
    71  		Scenarios:      config.Scenarios,
    72  		UserAgent:      config.UserAgent,
    73  		VersionPrefix:  config.VersionPrefix,
    74  		UpdateScenario: config.UpdateScenario,
    75  	}
    76  
    77  	transport, baseURL := createTransport(config.URL)
    78  	if transport != nil {
    79  		t.Transport = transport
    80  	}
    81  
    82  	t.URL = baseURL
    83  
    84  	tlsconfig := tls.Config{InsecureSkipVerify: InsecureSkipVerify}
    85  	tlsconfig.RootCAs = CaCertPool
    86  
    87  	if Cert != nil {
    88  		tlsconfig.Certificates = []tls.Certificate{*Cert}
    89  	}
    90  
    91  	if ht, ok := http.DefaultTransport.(*http.Transport); ok {
    92  		ht.TLSClientConfig = &tlsconfig
    93  	}
    94  
    95  	c := &ApiClient{client: t.Client(), BaseURL: baseURL, UserAgent: config.UserAgent, URLPrefix: config.VersionPrefix, PapiURL: config.PapiURL}
    96  	c.common.client = c
    97  	c.Decisions = (*DecisionsService)(&c.common)
    98  	c.Alerts = (*AlertsService)(&c.common)
    99  	c.Auth = (*AuthService)(&c.common)
   100  	c.Metrics = (*MetricsService)(&c.common)
   101  	c.Signal = (*SignalService)(&c.common)
   102  	c.DecisionDelete = (*DecisionDeleteService)(&c.common)
   103  	c.HeartBeat = (*HeartBeatService)(&c.common)
   104  
   105  	return c, nil
   106  }
   107  
   108  func NewDefaultClient(URL *url.URL, prefix string, userAgent string, client *http.Client) (*ApiClient, error) {
   109  	transport, baseURL := createTransport(URL)
   110  
   111  	if client == nil {
   112  		client = &http.Client{}
   113  
   114  		if transport != nil {
   115  			client.Transport = transport
   116  		} else {
   117  			if ht, ok := http.DefaultTransport.(*http.Transport); ok {
   118  				tlsconfig := tls.Config{InsecureSkipVerify: InsecureSkipVerify}
   119  				tlsconfig.RootCAs = CaCertPool
   120  
   121  				if Cert != nil {
   122  					tlsconfig.Certificates = []tls.Certificate{*Cert}
   123  				}
   124  
   125  				ht.TLSClientConfig = &tlsconfig
   126  				client.Transport = ht
   127  			}
   128  		}
   129  	}
   130  
   131  	c := &ApiClient{client: client, BaseURL: baseURL, UserAgent: userAgent, URLPrefix: prefix}
   132  	c.common.client = c
   133  	c.Decisions = (*DecisionsService)(&c.common)
   134  	c.Alerts = (*AlertsService)(&c.common)
   135  	c.Auth = (*AuthService)(&c.common)
   136  	c.Metrics = (*MetricsService)(&c.common)
   137  	c.Signal = (*SignalService)(&c.common)
   138  	c.DecisionDelete = (*DecisionDeleteService)(&c.common)
   139  	c.HeartBeat = (*HeartBeatService)(&c.common)
   140  
   141  	return c, nil
   142  }
   143  
   144  func RegisterClient(config *Config, client *http.Client) (*ApiClient, error) {
   145  	transport, baseURL := createTransport(config.URL)
   146  
   147  	if client == nil {
   148  		client = &http.Client{}
   149  		if transport != nil {
   150  			client.Transport = transport
   151  		} else {
   152  			tlsconfig := tls.Config{InsecureSkipVerify: InsecureSkipVerify}
   153  			if Cert != nil {
   154  				tlsconfig.RootCAs = CaCertPool
   155  				tlsconfig.Certificates = []tls.Certificate{*Cert}
   156  			}
   157  
   158  			http.DefaultTransport.(*http.Transport).TLSClientConfig = &tlsconfig
   159  		}
   160  	} else if client.Transport == nil && transport != nil {
   161  		client.Transport = transport
   162  	}
   163  
   164  	c := &ApiClient{client: client, BaseURL: baseURL, UserAgent: config.UserAgent, URLPrefix: config.VersionPrefix}
   165  	c.common.client = c
   166  	c.Decisions = (*DecisionsService)(&c.common)
   167  	c.Alerts = (*AlertsService)(&c.common)
   168  	c.Auth = (*AuthService)(&c.common)
   169  
   170  	resp, err := c.Auth.RegisterWatcher(context.Background(), models.WatcherRegistrationRequest{MachineID: &config.MachineID, Password: &config.Password})
   171  	/*if we have http status, return it*/
   172  	if err != nil {
   173  		if resp != nil && resp.Response != nil {
   174  			return nil, fmt.Errorf("api register (%s) http %s: %w", c.BaseURL, resp.Response.Status, err)
   175  		}
   176  
   177  		return nil, fmt.Errorf("api register (%s): %w", c.BaseURL, err)
   178  	}
   179  
   180  	return c, nil
   181  }
   182  
   183  func createTransport(url *url.URL) (*http.Transport, *url.URL) {
   184  	urlString := url.String()
   185  
   186  	// TCP transport
   187  	if !strings.HasPrefix(urlString, "/") {
   188  		return nil, url
   189  	}
   190  
   191  	// Unix transport
   192  	url.Path = "/"
   193  	url.Host = "unix"
   194  	url.Scheme = "http"
   195  
   196  	return &http.Transport{
   197  		DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
   198  			return net.Dial("unix", strings.TrimSuffix(urlString, "/"))
   199  		},
   200  	}, url
   201  }
   202  
   203  type Response struct {
   204  	Response *http.Response
   205  	// add our pagination stuff
   206  	// NextPage int
   207  	// ...
   208  }
   209  
   210  func newResponse(r *http.Response) *Response {
   211  	return &Response{Response: r}
   212  }
   213  
   214  type ListOpts struct {
   215  	// Page    int
   216  	// PerPage int
   217  }
   218  
   219  type DeleteOpts struct {
   220  	// ??
   221  }
   222  
   223  type AddOpts struct {
   224  	// ??
   225  }