From 3a2e5a11df13f55a99d31fd11bbcda2a30252b23 Mon Sep 17 00:00:00 2001 From: beatz174-bit Date: Fri, 24 Apr 2026 06:28:38 +1000 Subject: [PATCH] Normalize zone-style DNS record content from Dynu API --- internal/dynuclient/client.go | 22 ++++++++++++++++++ internal/dynuclient/client_test.go | 37 ++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/internal/dynuclient/client.go b/internal/dynuclient/client.go index 0b80c72..5864134 100644 --- a/internal/dynuclient/client.go +++ b/internal/dynuclient/client.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "net/url" + "regexp" "strings" "time" ) @@ -189,6 +190,9 @@ func (c *Client) ListDNSRecords(ctx context.Context, domainID int64) ([]DNSRecor if err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/dns/%d/record", domainID), nil, &resp); err != nil { return nil, err } + for i := range resp.DNSRecords { + normalizeDNSRecord(&resp.DNSRecords[i]) + } return resp.DNSRecords, nil } @@ -197,6 +201,7 @@ func (c *Client) GetDNSRecord(ctx context.Context, domainID int64, recordID int6 if err := c.doRequest(ctx, http.MethodGet, fmt.Sprintf("/dns/%d/record/%d", domainID, recordID), nil, &resp); err != nil { return nil, err } + normalizeDNSRecord(&resp.DNSRecord) return &resp.DNSRecord, nil } @@ -205,6 +210,7 @@ func (c *Client) CreateDNSRecord(ctx context.Context, domainID int64, req Create if err := c.doRequest(ctx, http.MethodPost, fmt.Sprintf("/dns/%d/record", domainID), buildDNSRecordUpsertPayload(req.RecordType, req.NodeName, req.Content, req.TTL, req.State, req.Group, req.Host), &resp); err != nil { return nil, err } + normalizeDNSRecord(&resp.DNSRecord) return &resp.DNSRecord, nil } @@ -213,6 +219,7 @@ func (c *Client) UpdateDNSRecord(ctx context.Context, domainID int64, recordID i if err := c.doRequest(ctx, http.MethodPut, fmt.Sprintf("/dns/%d/record/%d", domainID, recordID), buildDNSRecordUpsertPayload(req.RecordType, req.NodeName, req.Content, req.TTL, req.State, req.Group, req.Host), &resp); err != nil { return nil, err } + normalizeDNSRecord(&resp.DNSRecord) return &resp.DNSRecord, nil } @@ -338,3 +345,18 @@ func buildDNSRecordUpsertPayload(recordType string, nodeName string, content str return payload } + +var zoneStyleContentPattern = regexp.MustCompile(`(?i)^\S+\.\s+\d+\s+IN\s+\S+\s+(.+)$`) + +func normalizeDNSRecord(record *DNSRecord) { + if record == nil { + return + } + + matches := zoneStyleContentPattern.FindStringSubmatch(strings.TrimSpace(record.Content)) + if len(matches) != 2 { + return + } + + record.Content = strings.TrimSpace(matches[1]) +} diff --git a/internal/dynuclient/client_test.go b/internal/dynuclient/client_test.go index 7074e67..c8d6c41 100644 --- a/internal/dynuclient/client_test.go +++ b/internal/dynuclient/client_test.go @@ -191,6 +191,43 @@ func TestClientCreateDNSRecordSendsIPv4AddressForARecord(t *testing.T) { } } +func TestClientCreateDNSRecordNormalizesZoneStyleContent(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost || r.URL.Path != "/dns/1001/record" { + t.Fatalf("unexpected request %s %s", r.Method, r.URL.Path) + } + + _ = json.NewEncoder(w).Encode(map[string]any{ + "statusCode": 200, + "id": 10, + "domainId": 1001, + "domainName": "example.com", + "nodeName": "www", + "hostname": "www.example.com", + "recordType": "A", + "content": "www.example.com. 300 IN A 167.179.167.166", + "ttl": 300, + "state": true, + }) + })) + defer server.Close() + + client := dynuclient.New("test-key", dynuclient.WithBaseURL(server.URL), dynuclient.WithHTTPClient(server.Client())) + record, err := client.CreateDNSRecord(context.Background(), 1001, dynuclient.CreateDNSRecordRequest{ + NodeName: "www", + RecordType: "A", + Content: "167.179.167.166", + TTL: 300, + }) + if err != nil { + t.Fatalf("CreateDNSRecord() error = %v", err) + } + + if record.Content != "167.179.167.166" { + t.Fatalf("expected normalized content, got %q", record.Content) + } +} + func TestClientDoRequestTopLevelAPIExceptionPayload(t *testing.T) { fake := fakedynu.NewServer() defer fake.Close()