Files
WddSuperAgent/agent-wdd/cloudflare/Zone.go

237 lines
6.7 KiB
Go

package cloudflare
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"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 {
// tc.hk.107421.xyz ipv6.t2.107421.xyz 转换为 107421.xyz
// 寻找.的个数 如果大于 从后往前找到 第二个 . 的位置
dotCount := strings.Count(identifier, ".")
if dotCount > 1 {
// 从后往前找到 第二个 . 的位置
lastDotIndex := strings.LastIndex(identifier, ".")
secondLastDotIndex := strings.LastIndex(identifier[:lastDotIndex], ".")
identifier = identifier[secondLastDotIndex+1:]
} else if dotCount == 0 {
// 没有. 报错
log.Error("未找到域名 %s 的ZoneID", identifier)
return nil, fmt.Errorf("no zone found with name: %s", identifier)
}
log.Debug("转换后的域名: %s", identifier)
// 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
}