Files
Sankofa/crossplane-provider-proxmox/pkg/cloudflare/client.go
defiQUG 9daf1fd378 Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution
- Enhance API schema with expanded type definitions and resolvers
- Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth
- Implement new services: AI optimization, billing, blockchain, compliance, marketplace
- Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage)
- Update Crossplane provider with enhanced VM management capabilities
- Add comprehensive test suite for API endpoints and services
- Update frontend components with improved GraphQL subscriptions and real-time updates
- Enhance security configurations and headers (CSP, CORS, etc.)
- Update documentation and configuration files
- Add new CI/CD workflows and validation scripts
- Implement design system improvements and UI enhancements
2025-12-12 18:01:35 -08:00

272 lines
6.4 KiB
Go

package cloudflare
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/pkg/errors"
)
// Client represents a Cloudflare API client
type Client struct {
apiToken string
accountID string
httpClient *http.Client
baseURL string
}
// NewClient creates a new Cloudflare API client
func NewClient(apiToken, accountID string) *Client {
return &Client{
apiToken: apiToken,
accountID: accountID,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
baseURL: "https://api.cloudflare.com/client/v4",
}
}
// makeRequest makes an HTTP request to the Cloudflare API
func (c *Client) makeRequest(ctx context.Context, method, path string, body interface{}) (*http.Response, error) {
var reqBody io.Reader
if body != nil {
jsonData, err := json.Marshal(body)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal request body")
}
reqBody = bytes.NewBuffer(jsonData)
}
url := c.baseURL + path
req, err := http.NewRequestWithContext(ctx, method, url, reqBody)
if err != nil {
return nil, errors.Wrap(err, "failed to create request")
}
req.Header.Set("Authorization", "Bearer "+c.apiToken)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "request failed")
}
return resp, nil
}
// parseResponse parses the Cloudflare API response
func (c *Client) parseResponse(resp *http.Response, result interface{}) error {
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
bodyBytes, _ := io.ReadAll(resp.Body)
return fmt.Errorf("API error: %d %s - %s", resp.StatusCode, resp.Status, string(bodyBytes))
}
if result != nil {
if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
return errors.Wrap(err, "failed to decode response")
}
}
return nil
}
// Tunnel represents a Cloudflare Tunnel
type Tunnel struct {
ID string
Name string
Status string
Connections int
CreatedAt time.Time
}
// DNSRecord represents a DNS record
type DNSRecord struct {
ID string
Type string
Name string
Content string
TTL int
ZoneID string
ZoneName string
}
// ZeroTrustPolicy represents a Zero Trust access policy
type ZeroTrustPolicy struct {
ID string
Name string
Decision string
Include []map[string]interface{}
Exclude []map[string]interface{}
Require []map[string]interface{}
}
// ListTunnels lists all Cloudflare Tunnels
func (c *Client) ListTunnels(ctx context.Context) ([]Tunnel, error) {
resp, err := c.makeRequest(ctx, "GET", fmt.Sprintf("/accounts/%s/cfd_tunnel", c.accountID), nil)
if err != nil {
return nil, err
}
var apiResponse struct {
Success bool `json:"success"`
Result []struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
Connections int `json:"connections"`
CreatedAt time.Time `json:"created_at"`
} `json:"result"`
Errors []interface{} `json:"errors"`
}
if err := c.parseResponse(resp, &apiResponse); err != nil {
return nil, err
}
if !apiResponse.Success {
return nil, fmt.Errorf("API returned success=false")
}
tunnels := make([]Tunnel, len(apiResponse.Result))
for i, t := range apiResponse.Result {
tunnels[i] = Tunnel{
ID: t.ID,
Name: t.Name,
Status: t.Status,
Connections: t.Connections,
CreatedAt: t.CreatedAt,
}
}
return tunnels, nil
}
// ListDNSRecords lists DNS records for a zone
func (c *Client) ListDNSRecords(ctx context.Context, zoneID string) ([]DNSRecord, error) {
resp, err := c.makeRequest(ctx, "GET", fmt.Sprintf("/zones/%s/dns_records", zoneID), nil)
if err != nil {
return nil, err
}
var apiResponse struct {
Success bool `json:"success"`
Result []struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Content string `json:"content"`
TTL int `json:"ttl"`
ZoneID string `json:"zone_id"`
ZoneName string `json:"zone_name"`
} `json:"result"`
Errors []interface{} `json:"errors"`
}
if err := c.parseResponse(resp, &apiResponse); err != nil {
return nil, err
}
if !apiResponse.Success {
return nil, fmt.Errorf("API returned success=false")
}
records := make([]DNSRecord, len(apiResponse.Result))
for i, r := range apiResponse.Result {
records[i] = DNSRecord{
ID: r.ID,
Type: r.Type,
Name: r.Name,
Content: r.Content,
TTL: r.TTL,
ZoneID: r.ZoneID,
ZoneName: r.ZoneName,
}
}
return records, nil
}
// ListZones lists all DNS zones
func (c *Client) ListZones(ctx context.Context) ([]string, error) {
resp, err := c.makeRequest(ctx, "GET", "/zones", nil)
if err != nil {
return nil, err
}
var apiResponse struct {
Success bool `json:"success"`
Result []struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"result"`
Errors []interface{} `json:"errors"`
}
if err := c.parseResponse(resp, &apiResponse); err != nil {
return nil, err
}
if !apiResponse.Success {
return nil, fmt.Errorf("API returned success=false")
}
zoneIDs := make([]string, len(apiResponse.Result))
for i, z := range apiResponse.Result {
zoneIDs[i] = z.ID
}
return zoneIDs, nil
}
// ListZeroTrustPolicies lists Zero Trust access policies
func (c *Client) ListZeroTrustPolicies(ctx context.Context) ([]ZeroTrustPolicy, error) {
resp, err := c.makeRequest(ctx, "GET", fmt.Sprintf("/accounts/%s/access/policies", c.accountID), nil)
if err != nil {
return nil, err
}
var apiResponse struct {
Success bool `json:"success"`
Result []struct {
ID string `json:"id"`
Name string `json:"name"`
Decision string `json:"decision"`
Include []map[string]interface{} `json:"include"`
Exclude []map[string]interface{} `json:"exclude"`
Require []map[string]interface{} `json:"require"`
} `json:"result"`
Errors []interface{} `json:"errors"`
}
if err := c.parseResponse(resp, &apiResponse); err != nil {
return nil, err
}
if !apiResponse.Success {
return nil, fmt.Errorf("API returned success=false")
}
policies := make([]ZeroTrustPolicy, len(apiResponse.Result))
for i, p := range apiResponse.Result {
policies[i] = ZeroTrustPolicy{
ID: p.ID,
Name: p.Name,
Decision: p.Decision,
Include: p.Include,
Exclude: p.Exclude,
Require: p.Require,
}
}
return policies, nil
}