package cloudflare import ( "encoding/json" "fmt" "net/http" "net/url" "agent-wdd/log" ) // Zone represents a Cloudflare zone (domain) type Zone struct { ID string `json:"id"` Name string `json:"name"` Status string `json:"status"` Paused bool `json:"paused"` Type string `json:"type"` DevelopmentMode int `json:"development_mode"` NameServers []string `json:"name_servers"` OriginalNameServers []string `json:"original_name_servers"` OriginalRegistrar interface{} `json:"original_registrar"` OriginalDNSHost interface{} `json:"original_dnshost"` ModifiedOn string `json:"modified_on"` CreatedOn string `json:"created_on"` ActivatedOn string `json:"activated_on"` Meta ZoneMeta `json:"meta"` Owner Owner `json:"owner"` Account Account `json:"account"` Tenant Tenant `json:"tenant"` TenantUnit TenantUnit `json:"tenant_unit"` Permissions []string `json:"permissions"` Plan Plan `json:"plan"` } // ZoneMeta contains zone metadata type ZoneMeta struct { Step int `json:"step"` CustomCertificateQuota int `json:"custom_certificate_quota"` PageRuleQuota int `json:"page_rule_quota"` PhishingDetected bool `json:"phishing_detected"` } // Owner represents the owner of a zone type Owner struct { ID interface{} `json:"id"` Type string `json:"type"` Email interface{} `json:"email"` } // Account represents a Cloudflare account type Account struct { ID string `json:"id"` Name string `json:"name"` } // Tenant represents a tenant type Tenant struct { ID interface{} `json:"id"` Name interface{} `json:"name"` } // TenantUnit represents a tenant unit type TenantUnit struct { ID interface{} `json:"id"` } // Plan represents a zone plan type Plan struct { ID string `json:"id"` Name string `json:"name"` Price int `json:"price"` Currency string `json:"currency"` Frequency string `json:"frequency"` IsSubscribed bool `json:"is_subscribed"` CanSubscribe bool `json:"can_subscribe"` LegacyID string `json:"legacy_id"` LegacyDiscount bool `json:"legacy_discount"` ExternallyManaged bool `json:"externally_managed"` } // ZoneFilter represents filters for listing zones type ZoneFilter struct { Name string Status string Page int PerPage int Direction string Match string } // ListZones retrieves a list of zones from Cloudflare based on the provided filters // // Parameters: // - filter: Optional filter to apply to the zone list // // Returns: // - []Zone: List of zones // - error: Any errors that occurred during the request func (c *CloudflareClient) ListZones(filter *ZoneFilter) ([]Zone, error) { log.Debug("Listing zones with filter: %+v", filter) // Build URL and query parameters endpoint := fmt.Sprintf("%s/zones", c.baseURL) u, err := url.Parse(endpoint) if err != nil { log.Error("Failed to parse URL: %v", err) return nil, fmt.Errorf("failed to parse URL: %w", err) } q := u.Query() if filter != nil { if filter.Name != "" { q.Add("name", filter.Name) } if filter.Status != "" { q.Add("status", filter.Status) } if filter.Page > 0 { q.Add("page", fmt.Sprintf("%d", filter.Page)) } if filter.PerPage > 0 { q.Add("per_page", fmt.Sprintf("%d", filter.PerPage)) } if filter.Direction != "" { q.Add("direction", filter.Direction) } if filter.Match != "" { q.Add("match", filter.Match) } } u.RawQuery = q.Encode() // Make request resp, err := c.doRequest(http.MethodGet, u.String(), nil) if err != nil { log.Error("Failed to list zones: %v", err) return nil, fmt.Errorf("failed to list zones: %w", err) } // Parse response var zones []Zone result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &zones); err != nil { log.Error("Failed to unmarshal zones: %v", err) return nil, fmt.Errorf("failed to unmarshal zones: %w", err) } log.Info("Successfully retrieved %d zones", len(zones)) return zones, nil } // GetZone retrieves details of a specific zone by ID or name // // Parameters: // - identifier: The zone ID or domain name // // Returns: // - *Zone: The zone details // - error: Any errors that occurred during the request func (c *CloudflareClient) GetZone(identifier string) (*Zone, error) { log.Debug("Getting zone details for identifier: %s", identifier) // Determine if identifier is an ID or a domain name isID := true for _, char := range identifier { if (char < '0' || char > '9') && (char < 'a' || char > 'f') && (char < 'A' || char > 'F') { isID = false break } } var endpoint string if isID { endpoint = fmt.Sprintf("%s/zones/%s", c.baseURL, identifier) } else { // List zones with name filter zones, err := c.ListZones(&ZoneFilter{Name: identifier}) if err != nil { return nil, err } if len(zones) == 0 { log.Error("No zone found with name: %s", identifier) return nil, fmt.Errorf("no zone found with name: %s", identifier) } endpoint = fmt.Sprintf("%s/zones/%s", c.baseURL, zones[0].ID) } // Make request resp, err := c.doRequest(http.MethodGet, endpoint, nil) if err != nil { log.Error("Failed to get zone: %v", err) return nil, fmt.Errorf("failed to get zone: %w", err) } // Parse response var zone Zone result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &zone); err != nil { log.Error("Failed to unmarshal zone: %v", err) return nil, fmt.Errorf("failed to unmarshal zone: %w", err) } log.Info("Successfully retrieved zone: %s (%s)", zone.Name, zone.ID) return &zone, nil }