feat: authenticate users and agents requests
This commit is contained in:
@ -13,44 +13,49 @@ import (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
http *http.Client
|
||||
token string
|
||||
serverURL string
|
||||
http *http.Client
|
||||
defaultOpts Options
|
||||
serverURL string
|
||||
}
|
||||
|
||||
func (c *Client) apiGet(ctx context.Context, path string, result any) error {
|
||||
if err := c.apiDo(ctx, http.MethodGet, path, nil, result); err != nil {
|
||||
func (c *Client) apiGet(ctx context.Context, path string, result any, funcs ...OptionFunc) error {
|
||||
if err := c.apiDo(ctx, http.MethodGet, path, nil, result, funcs...); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) apiPost(ctx context.Context, path string, payload any, result any) error {
|
||||
if err := c.apiDo(ctx, http.MethodPost, path, payload, result); err != nil {
|
||||
func (c *Client) apiPost(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
|
||||
if err := c.apiDo(ctx, http.MethodPost, path, payload, result, funcs...); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) apiPut(ctx context.Context, path string, payload any, result any) error {
|
||||
if err := c.apiDo(ctx, http.MethodPut, path, payload, result); err != nil {
|
||||
func (c *Client) apiPut(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
|
||||
if err := c.apiDo(ctx, http.MethodPut, path, payload, result, funcs...); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) apiDelete(ctx context.Context, path string, payload any, result any) error {
|
||||
if err := c.apiDo(ctx, http.MethodDelete, path, payload, result); err != nil {
|
||||
func (c *Client) apiDelete(ctx context.Context, path string, payload any, result any, funcs ...OptionFunc) error {
|
||||
if err := c.apiDo(ctx, http.MethodDelete, path, payload, result, funcs...); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) apiDo(ctx context.Context, method string, path string, payload any, response any) error {
|
||||
func (c *Client) apiDo(ctx context.Context, method string, path string, payload any, response any, funcs ...OptionFunc) error {
|
||||
opts := c.defaultOptions()
|
||||
for _, fn := range funcs {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
url := c.serverURL + path
|
||||
|
||||
logger.Debug(
|
||||
@ -73,6 +78,12 @@ func (c *Client) apiDo(ctx context.Context, method string, path string, payload
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
for key, values := range opts.Headers {
|
||||
for _, v := range values {
|
||||
req.Header.Add(key, v)
|
||||
}
|
||||
}
|
||||
|
||||
res, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
@ -89,6 +100,12 @@ func (c *Client) apiDo(ctx context.Context, method string, path string, payload
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) defaultOptions() *Options {
|
||||
return &Options{
|
||||
Headers: c.defaultOpts.Headers,
|
||||
}
|
||||
}
|
||||
|
||||
func withResponse[T any]() struct {
|
||||
Data T
|
||||
Error *api.Error
|
||||
@ -113,9 +130,15 @@ func joinSlice[T any](items []T) string {
|
||||
return str
|
||||
}
|
||||
|
||||
func New(serverURL string) *Client {
|
||||
func New(serverURL string, funcs ...OptionFunc) *Client {
|
||||
opts := Options{}
|
||||
for _, fn := range funcs {
|
||||
fn(&opts)
|
||||
}
|
||||
|
||||
return &Client{
|
||||
serverURL: serverURL,
|
||||
http: &http.Client{},
|
||||
serverURL: serverURL,
|
||||
http: &http.Client{},
|
||||
defaultOpts: opts,
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *Client) GetAgent(ctx context.Context, agentID datastore.AgentID) (*datastore.Agent, error) {
|
||||
func (c *Client) GetAgent(ctx context.Context, agentID datastore.AgentID, funcs ...OptionFunc) (*datastore.Agent, error) {
|
||||
response := withResponse[struct {
|
||||
Agent *datastore.Agent `json:"agent"`
|
||||
}]()
|
||||
|
||||
path := fmt.Sprintf("/api/v1/agents/%d", agentID)
|
||||
|
||||
if err := c.apiGet(ctx, path, &response); err != nil {
|
||||
if err := c.apiGet(ctx, path, &response, funcs...); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *Client) GetAgentSpecs(ctx context.Context, agentID datastore.AgentID) ([]spec.Spec, error) {
|
||||
func (c *Client) GetAgentSpecs(ctx context.Context, agentID datastore.AgentID, funcs ...OptionFunc) ([]spec.Spec, error) {
|
||||
response := withResponse[struct {
|
||||
Specs []*spec.RawSpec `json:"specs"`
|
||||
}]()
|
||||
|
||||
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
|
||||
|
||||
if err := c.apiGet(ctx, path, &response); err != nil {
|
||||
if err := c.apiGet(ctx, path, &response, funcs...); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
24
internal/client/options.go
Normal file
24
internal/client/options.go
Normal file
@ -0,0 +1,24 @@
|
||||
package client
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Options struct {
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
type OptionFunc func(*Options)
|
||||
|
||||
func WithToken(token string) OptionFunc {
|
||||
return func(o *Options) {
|
||||
if o.Headers == nil {
|
||||
o.Headers = http.Header{}
|
||||
}
|
||||
o.Headers.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
}
|
||||
|
||||
func WithHeaders(headers http.Header) OptionFunc {
|
||||
return func(o *Options) {
|
||||
o.Headers = headers
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import (
|
||||
type QueryAgentsOptionFunc func(*QueryAgentsOptions)
|
||||
|
||||
type QueryAgentsOptions struct {
|
||||
Options []OptionFunc
|
||||
Limit *int
|
||||
Offset *int
|
||||
Thumbprints []string
|
||||
@ -19,6 +20,12 @@ type QueryAgentsOptions struct {
|
||||
Statuses []datastore.AgentStatus
|
||||
}
|
||||
|
||||
func WithQueryAgentsOptions(funcs ...OptionFunc) QueryAgentsOptionFunc {
|
||||
return func(opts *QueryAgentsOptions) {
|
||||
opts.Options = funcs
|
||||
}
|
||||
}
|
||||
|
||||
func WithQueryAgentsLimit(limit int) QueryAgentsOptionFunc {
|
||||
return func(opts *QueryAgentsOptions) {
|
||||
opts.Limit = &limit
|
||||
@ -76,7 +83,11 @@ func (c *Client) QueryAgents(ctx context.Context, funcs ...QueryAgentsOptionFunc
|
||||
Total int `json:"total"`
|
||||
}]()
|
||||
|
||||
if err := c.apiGet(ctx, path, &response); err != nil {
|
||||
if options.Options == nil {
|
||||
options.Options = make([]OptionFunc, 0)
|
||||
}
|
||||
|
||||
if err := c.apiGet(ctx, path, &response, options.Options...); err != nil {
|
||||
return nil, 0, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint string, meta []metadata.Tuple) (*datastore.Agent, error) {
|
||||
func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint string, meta []metadata.Tuple, funcs ...OptionFunc) (*datastore.Agent, error) {
|
||||
keySet, err := jwk.PublicKeySet(key)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
@ -36,7 +36,7 @@ func (c *Client) RegisterAgent(ctx context.Context, key jwk.Key, thumbprint stri
|
||||
Agent *datastore.Agent `json:"agent"`
|
||||
}]()
|
||||
|
||||
if err := c.apiPost(ctx, "/api/v1/register", payload, &response); err != nil {
|
||||
if err := c.apiPost(ctx, "/api/v1/register", payload, &response, funcs...); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type UpdateAgentOptions struct {
|
||||
Status *int
|
||||
Status *int
|
||||
Options []OptionFunc
|
||||
}
|
||||
|
||||
type UpdateAgentOptionFunc func(*UpdateAgentOptions)
|
||||
@ -20,6 +21,12 @@ func WithAgentStatus(status int) UpdateAgentOptionFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func WithUpdateAgentsOptions(funcs ...OptionFunc) UpdateAgentOptionFunc {
|
||||
return func(opts *UpdateAgentOptions) {
|
||||
opts.Options = funcs
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) UpdateAgent(ctx context.Context, agentID datastore.AgentID, funcs ...UpdateAgentOptionFunc) (*datastore.Agent, error) {
|
||||
opts := &UpdateAgentOptions{}
|
||||
for _, fn := range funcs {
|
||||
@ -38,7 +45,11 @@ func (c *Client) UpdateAgent(ctx context.Context, agentID datastore.AgentID, fun
|
||||
|
||||
path := fmt.Sprintf("/api/v1/agents/%d", agentID)
|
||||
|
||||
if err := c.apiPut(ctx, path, payload, &response); err != nil {
|
||||
if opts.Options == nil {
|
||||
opts.Options = make([]OptionFunc, 0)
|
||||
}
|
||||
|
||||
if err := c.apiPut(ctx, path, payload, &response, opts.Options...); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID, spc spec.Spec) (*datastore.Spec, error) {
|
||||
func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID, spc spec.Spec, funcs ...OptionFunc) (*datastore.Spec, error) {
|
||||
payload := struct {
|
||||
Name spec.Name `json:"name"`
|
||||
Revision int `json:"revision"`
|
||||
@ -27,7 +27,7 @@ func (c *Client) UpdateAgentSpec(ctx context.Context, agentID datastore.AgentID,
|
||||
|
||||
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
|
||||
|
||||
if err := c.apiPost(ctx, path, payload, &response); err != nil {
|
||||
if err := c.apiPost(ctx, path, payload, &response, funcs...); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user