tokens.go raw

   1  package desec
   2  
   3  import (
   4  	"context"
   5  	"fmt"
   6  	"net/http"
   7  	"time"
   8  )
   9  
  10  // Token a token representation.
  11  //
  12  // https://desec.readthedocs.io/en/latest/auth/tokens.html#token-field-reference
  13  type Token struct {
  14  	ID               string     `json:"id,omitempty"`
  15  	Created          *time.Time `json:"created,omitempty"`
  16  	LastUsed         *time.Time `json:"last_used,omitempty"`
  17  	Owner            string     `json:"owner,omitempty"`
  18  	UserOverride     string     `json:"user_override,omitempty"`
  19  	Name             string     `json:"name,omitempty"`
  20  	PermCreateDomain bool       `json:"perm_create_domain"`
  21  	PermDeleteDomain bool       `json:"perm_delete_domain"`
  22  	PermManageTokens bool       `json:"perm_manage_tokens"`
  23  	IsValid          bool       `json:"is_valid,omitempty"`
  24  	AllowedSubnets   []string   `json:"allowed_subnets,omitempty"`
  25  	AutoPolicy       bool       `json:"auto_policy"`
  26  	Value            string     `json:"token,omitempty"`
  27  	// Not currently implemented
  28  	// MaxAge           *time.Duration `json:"name,omitempty"`
  29  	// MaxUnusedPeriod  *time.Duration `json:"name,omitempty"`
  30  }
  31  
  32  // TokensService handles communication with the tokens related methods of the deSEC API.
  33  //
  34  // https://desec.readthedocs.io/en/latest/auth/tokens.html
  35  type TokensService struct {
  36  	client *Client
  37  }
  38  
  39  // GetAll retrieving all current tokens.
  40  // https://desec.readthedocs.io/en/latest/auth/tokens.html#retrieving-all-current-tokens
  41  func (s *TokensService) GetAll(ctx context.Context) ([]Token, error) {
  42  	endpoint, err := s.client.createEndpoint("auth", "tokens")
  43  	if err != nil {
  44  		return nil, fmt.Errorf("failed to create endpoint: %w", err)
  45  	}
  46  
  47  	req, err := s.client.newRequest(ctx, http.MethodGet, endpoint, nil)
  48  	if err != nil {
  49  		return nil, err
  50  	}
  51  
  52  	resp, err := s.client.httpClient.Do(req)
  53  	if err != nil {
  54  		return nil, fmt.Errorf("failed to call API: %w", err)
  55  	}
  56  
  57  	defer func() { _ = resp.Body.Close() }()
  58  
  59  	if resp.StatusCode != http.StatusOK {
  60  		return nil, handleError(resp)
  61  	}
  62  
  63  	var tokens []Token
  64  
  65  	err = handleResponse(resp, &tokens)
  66  	if err != nil {
  67  		return nil, err
  68  	}
  69  
  70  	return tokens, nil
  71  }
  72  
  73  // Get retrieves a specific token.
  74  // https://desec.readthedocs.io/en/latest/auth/tokens.html#retrieving-a-specific-token
  75  // NOTE: This method used to retrieve all policies for a token, that is now done by GetAll.
  76  func (s *TokensService) Get(ctx context.Context, id string) (*Token, error) {
  77  	endpoint, err := s.client.createEndpoint("auth", "tokens", id)
  78  	if err != nil {
  79  		return nil, fmt.Errorf("failed to create endpoint: %w", err)
  80  	}
  81  
  82  	req, err := s.client.newRequest(ctx, http.MethodGet, endpoint, nil)
  83  	if err != nil {
  84  		return nil, err
  85  	}
  86  
  87  	resp, err := s.client.httpClient.Do(req)
  88  	if err != nil {
  89  		return nil, fmt.Errorf("failed to call API: %w", err)
  90  	}
  91  
  92  	defer func() { _ = resp.Body.Close() }()
  93  
  94  	if resp.StatusCode == http.StatusNotFound {
  95  		return nil, nil
  96  	}
  97  
  98  	if resp.StatusCode != http.StatusOK {
  99  		return nil, handleError(resp)
 100  	}
 101  
 102  	token := &Token{}
 103  
 104  	err = handleResponse(resp, token)
 105  	if err != nil {
 106  		return nil, err
 107  	}
 108  
 109  	return token, nil
 110  }
 111  
 112  // Create creates additional tokens.
 113  // https://desec.readthedocs.io/en/latest/auth/tokens.html#create-additional-tokens
 114  func (s *TokensService) Create(ctx context.Context, name string) (*Token, error) {
 115  	endpoint, err := s.client.createEndpoint("auth", "tokens")
 116  	if err != nil {
 117  		return nil, fmt.Errorf("failed to create endpoint: %w", err)
 118  	}
 119  
 120  	req, err := s.client.newRequest(ctx, http.MethodPost, endpoint, Token{Name: name})
 121  	if err != nil {
 122  		return nil, err
 123  	}
 124  
 125  	resp, err := s.client.httpClient.Do(req)
 126  	if err != nil {
 127  		return nil, fmt.Errorf("failed to call API: %w", err)
 128  	}
 129  
 130  	defer func() { _ = resp.Body.Close() }()
 131  
 132  	if resp.StatusCode != http.StatusCreated {
 133  		return nil, handleError(resp)
 134  	}
 135  
 136  	var token Token
 137  
 138  	err = handleResponse(resp, &token)
 139  	if err != nil {
 140  		return nil, err
 141  	}
 142  
 143  	return &token, nil
 144  }
 145  
 146  // Update a token.
 147  // https://desec.readthedocs.io/en/latest/auth/tokens.html#modifying-a-token
 148  func (s *TokensService) Update(ctx context.Context, id string, token *Token) (*Token, error) {
 149  	endpoint, err := s.client.createEndpoint("auth", "tokens", id)
 150  	if err != nil {
 151  		return nil, fmt.Errorf("failed to create endpoint: %w", err)
 152  	}
 153  
 154  	// Copy values, including only fields that can be modified
 155  	req, err := s.client.newRequest(ctx, http.MethodPatch, endpoint, Token{
 156  		Owner:            token.Owner,
 157  		UserOverride:     token.UserOverride,
 158  		Name:             token.Name,
 159  		PermCreateDomain: token.PermCreateDomain,
 160  		PermDeleteDomain: token.PermDeleteDomain,
 161  		PermManageTokens: token.PermManageTokens,
 162  		AllowedSubnets:   token.AllowedSubnets,
 163  		AutoPolicy:       token.AutoPolicy,
 164  	})
 165  	if err != nil {
 166  		return nil, err
 167  	}
 168  
 169  	resp, err := s.client.httpClient.Do(req)
 170  	if err != nil {
 171  		return nil, fmt.Errorf("failed to call API: %w", err)
 172  	}
 173  
 174  	defer func() { _ = resp.Body.Close() }()
 175  
 176  	if resp.StatusCode != http.StatusOK {
 177  		return nil, handleError(resp)
 178  	}
 179  
 180  	result := &Token{}
 181  
 182  	err = handleResponse(resp, result)
 183  	if err != nil {
 184  		return nil, err
 185  	}
 186  
 187  	return result, nil
 188  }
 189  
 190  // Delete deletes tokens.
 191  // https://desec.readthedocs.io/en/latest/auth/tokens.html#delete-tokens
 192  func (s *TokensService) Delete(ctx context.Context, tokenID string) error {
 193  	endpoint, err := s.client.createEndpoint("auth", "tokens", tokenID)
 194  	if err != nil {
 195  		return fmt.Errorf("failed to create endpoint: %w", err)
 196  	}
 197  
 198  	req, err := s.client.newRequest(ctx, http.MethodDelete, endpoint, nil)
 199  	if err != nil {
 200  		return err
 201  	}
 202  
 203  	resp, err := s.client.httpClient.Do(req)
 204  	if err != nil {
 205  		return fmt.Errorf("failed to call API: %w", err)
 206  	}
 207  
 208  	defer func() { _ = resp.Body.Close() }()
 209  
 210  	if resp.StatusCode != http.StatusNoContent {
 211  		return handleError(resp)
 212  	}
 213  
 214  	return nil
 215  }
 216