dnscontrol/pkg/cloudflare-go/api_token.go
Tom Limoncelli 7fd6a74e0c
CLOUDFLAREAPI: CF_REDIRECT/CF_TEMP_REDIRECT should dtrt using Single Redirects (#3002)
Co-authored-by: Josh Zhang <jzhang1@stackoverflow.com>
2024-06-18 17:38:50 -04:00

238 lines
7.4 KiB
Go

package cloudflare
import (
"context"
"fmt"
"net/http"
"time"
"github.com/goccy/go-json"
)
// APIToken is the full API token.
type APIToken struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Status string `json:"status,omitempty"`
IssuedOn *time.Time `json:"issued_on,omitempty"`
ModifiedOn *time.Time `json:"modified_on,omitempty"`
NotBefore *time.Time `json:"not_before,omitempty"`
ExpiresOn *time.Time `json:"expires_on,omitempty"`
Policies []APITokenPolicies `json:"policies,omitempty"`
Condition *APITokenCondition `json:"condition,omitempty"`
Value string `json:"value,omitempty"`
}
// APITokenPermissionGroups is the permission groups associated with API tokens.
type APITokenPermissionGroups struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Scopes []string `json:"scopes,omitempty"`
}
// APITokenPolicies are policies attached to an API token.
type APITokenPolicies struct {
ID string `json:"id,omitempty"`
Effect string `json:"effect"`
Resources map[string]interface{} `json:"resources"`
PermissionGroups []APITokenPermissionGroups `json:"permission_groups"`
}
// APITokenRequestIPCondition is the struct for adding an IP restriction to an
// API token.
type APITokenRequestIPCondition struct {
In []string `json:"in,omitempty"`
NotIn []string `json:"not_in,omitempty"`
}
// APITokenCondition is the outer structure for request conditions (currently
// only IPs).
type APITokenCondition struct {
RequestIP *APITokenRequestIPCondition `json:"request.ip,omitempty"`
}
// APITokenResponse is the API response for a single API token.
type APITokenResponse struct {
Response
Result APIToken `json:"result"`
}
// APITokenListResponse is the API response for multiple API tokens.
type APITokenListResponse struct {
Response
Result []APIToken `json:"result"`
}
// APITokenRollResponse is the API response when rolling the token.
type APITokenRollResponse struct {
Response
Result string `json:"result"`
}
// APITokenVerifyResponse is the API response for verifying a token.
type APITokenVerifyResponse struct {
Response
Result APITokenVerifyBody `json:"result"`
}
// APITokenPermissionGroupsResponse is the API response for the available
// permission groups.
type APITokenPermissionGroupsResponse struct {
Response
Result []APITokenPermissionGroups `json:"result"`
}
// APITokenVerifyBody is the API body for verifying a token.
type APITokenVerifyBody struct {
ID string `json:"id"`
Status string `json:"status"`
NotBefore time.Time `json:"not_before"`
ExpiresOn time.Time `json:"expires_on"`
}
// GetAPIToken returns a single API token based on the ID.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-token-details
func (api *API) GetAPIToken(ctx context.Context, tokenID string) (APIToken, error) {
uri := fmt.Sprintf("/user/tokens/%s", tokenID)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return APIToken{}, err
}
var apiTokenResponse APITokenResponse
err = json.Unmarshal(res, &apiTokenResponse)
if err != nil {
return APIToken{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return apiTokenResponse.Result, nil
}
// APITokens returns all available API tokens.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-list-tokens
func (api *API) APITokens(ctx context.Context) ([]APIToken, error) {
res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens", nil)
if err != nil {
return []APIToken{}, err
}
var apiTokenListResponse APITokenListResponse
err = json.Unmarshal(res, &apiTokenListResponse)
if err != nil {
return []APIToken{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return apiTokenListResponse.Result, nil
}
// CreateAPIToken creates a new token. Returns the API token that has been
// generated.
//
// The token value itself is only shown once (post create) and will present as
// `Value` from this method. If you fail to capture it at this point, you will
// need to roll the token in order to get a new value.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-create-token
func (api *API) CreateAPIToken(ctx context.Context, token APIToken) (APIToken, error) {
res, err := api.makeRequestContext(ctx, http.MethodPost, "/user/tokens", token)
if err != nil {
return APIToken{}, err
}
var createTokenAPIResponse APITokenResponse
err = json.Unmarshal(res, &createTokenAPIResponse)
if err != nil {
return APIToken{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return createTokenAPIResponse.Result, nil
}
// UpdateAPIToken updates an existing API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-update-token
func (api *API) UpdateAPIToken(ctx context.Context, tokenID string, token APIToken) (APIToken, error) {
res, err := api.makeRequestContext(ctx, http.MethodPut, "/user/tokens/"+tokenID, token)
if err != nil {
return APIToken{}, err
}
var updatedTokenResponse APITokenResponse
err = json.Unmarshal(res, &updatedTokenResponse)
if err != nil {
return APIToken{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return updatedTokenResponse.Result, nil
}
// RollAPIToken rolls the credential associated with the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-roll-token
func (api *API) RollAPIToken(ctx context.Context, tokenID string) (string, error) {
uri := fmt.Sprintf("/user/tokens/%s/value", tokenID)
res, err := api.makeRequestContext(ctx, http.MethodPut, uri, nil)
if err != nil {
return "", err
}
var apiTokenRollResponse APITokenRollResponse
err = json.Unmarshal(res, &apiTokenRollResponse)
if err != nil {
return "", fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return apiTokenRollResponse.Result, nil
}
// VerifyAPIToken tests the validity of the token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-verify-token
func (api *API) VerifyAPIToken(ctx context.Context) (APITokenVerifyBody, error) {
res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/verify", nil)
if err != nil {
return APITokenVerifyBody{}, err
}
var apiTokenVerifyResponse APITokenVerifyResponse
err = json.Unmarshal(res, &apiTokenVerifyResponse)
if err != nil {
return APITokenVerifyBody{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return apiTokenVerifyResponse.Result, nil
}
// DeleteAPIToken deletes a single API token.
//
// API reference: https://api.cloudflare.com/#user-api-tokens-delete-token
func (api *API) DeleteAPIToken(ctx context.Context, tokenID string) error {
_, err := api.makeRequestContext(ctx, http.MethodDelete, "/user/tokens/"+tokenID, nil)
if err != nil {
return err
}
return nil
}
// ListAPITokensPermissionGroups returns all available API token permission groups.
//
// API reference: https://api.cloudflare.com/#permission-groups-list-permission-groups
func (api *API) ListAPITokensPermissionGroups(ctx context.Context) ([]APITokenPermissionGroups, error) {
var r APITokenPermissionGroupsResponse
res, err := api.makeRequestContext(ctx, http.MethodGet, "/user/tokens/permission_groups", nil)
if err != nil {
return []APITokenPermissionGroups{}, err
}
err = json.Unmarshal(res, &r)
if err != nil {
return []APITokenPermissionGroups{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}
return r.Result, nil
}