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 }