mirror of
https://github.com/go-acme/lego.git
synced 2026-01-25 05:06:16 +00:00
autodns: use the right response structure (#2737)
This commit is contained in:
committed by
GitHub
parent
742741fe05
commit
cc83c025b5
@@ -128,7 +128,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
Value: info.Value,
|
||||
}}
|
||||
|
||||
_, err := d.client.AddTxtRecords(context.Background(), info.EffectiveFQDN, records)
|
||||
_, err := d.client.AddRecords(context.Background(), info.EffectiveFQDN, records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("autodns: %w", err)
|
||||
}
|
||||
@@ -147,7 +147,8 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
Value: info.Value,
|
||||
}}
|
||||
|
||||
if err := d.client.RemoveTXTRecords(context.Background(), info.EffectiveFQDN, records); err != nil {
|
||||
_, err := d.client.RemoveRecords(context.Background(), info.EffectiveFQDN, records)
|
||||
if err != nil {
|
||||
return fmt.Errorf("autodns: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,24 +43,22 @@ func NewClient(username, password string, clientContext int) *Client {
|
||||
}
|
||||
}
|
||||
|
||||
// AddTxtRecords adds TXT records.
|
||||
func (c *Client) AddTxtRecords(ctx context.Context, domain string, records []*ResourceRecord) (*Zone, error) {
|
||||
// AddRecords adds records.
|
||||
func (c *Client) AddRecords(ctx context.Context, domain string, records []*ResourceRecord) (*DataZoneResponse, error) {
|
||||
zoneStream := &ZoneStream{Adds: records}
|
||||
|
||||
return c.updateZone(ctx, domain, zoneStream)
|
||||
}
|
||||
|
||||
// RemoveTXTRecords removes TXT records.
|
||||
func (c *Client) RemoveTXTRecords(ctx context.Context, domain string, records []*ResourceRecord) error {
|
||||
// RemoveRecords removes records.
|
||||
func (c *Client) RemoveRecords(ctx context.Context, domain string, records []*ResourceRecord) (*DataZoneResponse, error) {
|
||||
zoneStream := &ZoneStream{Removes: records}
|
||||
|
||||
_, err := c.updateZone(ctx, domain, zoneStream)
|
||||
|
||||
return err
|
||||
return c.updateZone(ctx, domain, zoneStream)
|
||||
}
|
||||
|
||||
// https://github.com/InterNetX/domainrobot-api/blob/bdc8fe92a2f32fcbdb29e30bf6006ab446f81223/src/domainrobot.json#L21090
|
||||
func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *ZoneStream) (*Zone, error) {
|
||||
func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *ZoneStream) (*DataZoneResponse, error) {
|
||||
endpoint := c.BaseURL.JoinPath("zone", domain, "_stream")
|
||||
|
||||
req, err := newJSONRequest(ctx, http.MethodPost, endpoint, zoneStream)
|
||||
@@ -68,12 +66,12 @@ func (c *Client) updateZone(ctx context.Context, domain string, zoneStream *Zone
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var zone *Zone
|
||||
if err := c.do(req, &zone); err != nil {
|
||||
var resp *DataZoneResponse
|
||||
if err := c.do(req, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return zone, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) do(req *http.Request, result any) error {
|
||||
@@ -88,7 +86,7 @@ func (c *Client) do(req *http.Request, result any) error {
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
return errutils.NewUnexpectedResponseStatusCodeError(req, resp)
|
||||
return parseError(req, resp)
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
@@ -131,3 +129,16 @@ func newJSONRequest(ctx context.Context, method string, endpoint *url.URL, paylo
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func parseError(req *http.Request, resp *http.Response) error {
|
||||
raw, _ := io.ReadAll(resp.Body)
|
||||
|
||||
var errAPI APIError
|
||||
|
||||
err := json.Unmarshal(raw, &errAPI)
|
||||
if err != nil {
|
||||
return errutils.NewUnexpectedStatusCodeError(req, resp.StatusCode, raw)
|
||||
}
|
||||
|
||||
return &errAPI
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
@@ -24,7 +25,7 @@ func mockBuilder() *servermock.Builder[*Client] {
|
||||
WithJSONHeaders())
|
||||
}
|
||||
|
||||
func TestClient_AddTxtRecords(t *testing.T) {
|
||||
func TestClient_AddRecords(t *testing.T) {
|
||||
client := mockBuilder().
|
||||
Route("POST /zone/example.com/_stream",
|
||||
servermock.ResponseFromFixture("add_record.json"),
|
||||
@@ -33,28 +34,81 @@ func TestClient_AddTxtRecords(t *testing.T) {
|
||||
With("X-Domainrobot-Context", "123")).
|
||||
Build(t)
|
||||
|
||||
records := []*ResourceRecord{{}}
|
||||
records := []*ResourceRecord{{
|
||||
Name: "example.com",
|
||||
TTL: 600,
|
||||
Type: "TXT",
|
||||
Value: "txtTXTtxt",
|
||||
}}
|
||||
|
||||
zone, err := client.AddTxtRecords(t.Context(), "example.com", records)
|
||||
resp, err := client.AddRecords(t.Context(), "example.com", records)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := &Zone{
|
||||
Name: "example.com",
|
||||
ResourceRecords: []*ResourceRecord{{
|
||||
Name: "example.com",
|
||||
TTL: 120,
|
||||
Type: "TXT",
|
||||
Value: "txt",
|
||||
Pref: 1,
|
||||
}},
|
||||
Action: "xxx",
|
||||
VirtualNameServer: "yyy",
|
||||
expected := &DataZoneResponse{
|
||||
STID: "20251121-appf4923-126284",
|
||||
CTID: "",
|
||||
Messages: []ResponseMessage{
|
||||
{
|
||||
Text: "string",
|
||||
Messages: []string{
|
||||
"string",
|
||||
},
|
||||
Objects: []GenericObject{
|
||||
{
|
||||
Type: "string",
|
||||
Value: "string",
|
||||
},
|
||||
},
|
||||
Code: "string",
|
||||
Status: "SUCCESS",
|
||||
},
|
||||
},
|
||||
Status: &ResponseStatus{
|
||||
Code: "S0301",
|
||||
Text: "Zone was updated successfully on the name server.",
|
||||
Type: "SUCCESS",
|
||||
},
|
||||
Object: nil,
|
||||
Data: []Zone{
|
||||
{
|
||||
Name: "example.com",
|
||||
ResourceRecords: []ResourceRecord{
|
||||
{
|
||||
Name: "example.com",
|
||||
TTL: 120,
|
||||
Type: "TXT",
|
||||
Value: "txt",
|
||||
Pref: 1,
|
||||
},
|
||||
},
|
||||
Action: "xxx",
|
||||
VirtualNameServer: "yyy",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, zone)
|
||||
assert.Equal(t, expected, resp)
|
||||
}
|
||||
|
||||
func TestClient_RemoveTXTRecords(t *testing.T) {
|
||||
func TestClient_AddRecords_error(t *testing.T) {
|
||||
client := mockBuilder().
|
||||
Route("POST /zone/example.com/_stream",
|
||||
servermock.ResponseFromFixture("error.json").
|
||||
WithStatusCode(http.StatusBadRequest)).
|
||||
Build(t)
|
||||
|
||||
records := []*ResourceRecord{{
|
||||
Name: "example.com",
|
||||
TTL: 600,
|
||||
Type: "TXT",
|
||||
Value: "txtTXTtxt",
|
||||
}}
|
||||
|
||||
_, err := client.AddRecords(t.Context(), "example.com", records)
|
||||
require.EqualError(t, err, `STID: 20251121-appf4923-126284, status: code: E0202002, text: Zone konnte auf dem Nameserver nicht aktualisiert werden., type: ERROR, message: code: EF02022, text: Der Zusatzeintrag wurde doppelt eingetragen., status: ERROR, object: OURDOMAIN.TLD@nsa7.schlundtech.de/rr[17]: _acme-challenge.www.whoami.int.OURDOMAIN.TLD TXT "rK2SJb_ZcrYefbfCKU6jZEANfEAJeOtSh1Fv8hkUoVc"`)
|
||||
}
|
||||
|
||||
func TestClient_RemoveRecords(t *testing.T) {
|
||||
client := mockBuilder().
|
||||
Route("POST /zone/example.com/_stream",
|
||||
servermock.ResponseFromFixture("remove_record.json"),
|
||||
@@ -63,8 +117,58 @@ func TestClient_RemoveTXTRecords(t *testing.T) {
|
||||
With("X-Domainrobot-Context", "123")).
|
||||
Build(t)
|
||||
|
||||
records := []*ResourceRecord{{}}
|
||||
records := []*ResourceRecord{{
|
||||
Name: "example.com",
|
||||
TTL: 600,
|
||||
Type: "TXT",
|
||||
Value: "txtTXTtxt",
|
||||
}}
|
||||
|
||||
err := client.RemoveTXTRecords(t.Context(), "example.com", records)
|
||||
resp, err := client.RemoveRecords(t.Context(), "example.com", records)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := &DataZoneResponse{
|
||||
STID: "20251121-appf4923-126284",
|
||||
CTID: "",
|
||||
Messages: []ResponseMessage{
|
||||
{
|
||||
Text: "string",
|
||||
Messages: []string{
|
||||
"string",
|
||||
},
|
||||
Objects: []GenericObject{
|
||||
{
|
||||
Type: "string",
|
||||
Value: "string",
|
||||
},
|
||||
},
|
||||
Code: "string",
|
||||
Status: "SUCCESS",
|
||||
},
|
||||
},
|
||||
Status: &ResponseStatus{
|
||||
Code: "S0301",
|
||||
Text: "Zone was updated successfully on the name server.",
|
||||
Type: "SUCCESS",
|
||||
},
|
||||
Object: nil,
|
||||
Data: []Zone{
|
||||
{
|
||||
Name: "example.com",
|
||||
ResourceRecords: []ResourceRecord{
|
||||
{
|
||||
Name: "example.com",
|
||||
TTL: 120,
|
||||
Type: "TXT",
|
||||
Value: "txt",
|
||||
Pref: 1,
|
||||
},
|
||||
},
|
||||
Action: "xxx",
|
||||
VirtualNameServer: "yyy",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, resp)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"adds": [
|
||||
{
|
||||
"name": "",
|
||||
"ttl": 0,
|
||||
"type": "",
|
||||
"value": ""
|
||||
"name": "example.com",
|
||||
"ttl": 600,
|
||||
"type": "TXT",
|
||||
"value": "txtTXTtxt"
|
||||
}
|
||||
],
|
||||
"rems": null
|
||||
|
||||
@@ -1,14 +1,41 @@
|
||||
{
|
||||
"origin": "example.com",
|
||||
"resourceRecords": [
|
||||
"stid": "20251121-appf4923-126284",
|
||||
"messages": [
|
||||
{
|
||||
"name": "example.com",
|
||||
"ttl": 120,
|
||||
"type": "TXT",
|
||||
"value": "txt",
|
||||
"pref": 1
|
||||
"text": "string",
|
||||
"notice": "string",
|
||||
"messages": [
|
||||
"string"
|
||||
],
|
||||
"objects": [
|
||||
{
|
||||
"type": "string",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"code": "string",
|
||||
"status": "SUCCESS"
|
||||
}
|
||||
],
|
||||
"action": "xxx",
|
||||
"virtualNameServer": "yyy"
|
||||
"status": {
|
||||
"code": "S0301",
|
||||
"text": "Zone was updated successfully on the name server.",
|
||||
"type": "SUCCESS"
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"origin": "example.com",
|
||||
"resourceRecords": [
|
||||
{
|
||||
"name": "example.com",
|
||||
"ttl": 120,
|
||||
"type": "TXT",
|
||||
"value": "txt",
|
||||
"pref": 1
|
||||
}
|
||||
],
|
||||
"action": "xxx",
|
||||
"virtualNameServer": "yyy"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
21
providers/dns/autodns/internal/fixtures/error.json
Normal file
21
providers/dns/autodns/internal/fixtures/error.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"stid": "20251121-appf4923-126284",
|
||||
"messages": [
|
||||
{
|
||||
"text": "Der Zusatzeintrag wurde doppelt eingetragen.",
|
||||
"objects": [
|
||||
{
|
||||
"type": "OURDOMAIN.TLD@nsa7.schlundtech.de/rr[17]",
|
||||
"value": "_acme-challenge.www.whoami.int.OURDOMAIN.TLD TXT \"rK2SJb_ZcrYefbfCKU6jZEANfEAJeOtSh1Fv8hkUoVc\""
|
||||
}
|
||||
],
|
||||
"code": "EF02022",
|
||||
"status": "ERROR"
|
||||
}
|
||||
],
|
||||
"status": {
|
||||
"code": "E0202002",
|
||||
"text": "Zone konnte auf dem Nameserver nicht aktualisiert werden.",
|
||||
"type": "ERROR"
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
"adds": null,
|
||||
"rems": [
|
||||
{
|
||||
"name": "",
|
||||
"ttl": 0,
|
||||
"type": "",
|
||||
"value": ""
|
||||
"name": "example.com",
|
||||
"ttl": 600,
|
||||
"type": "TXT",
|
||||
"value": "txtTXTtxt"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,14 +1,41 @@
|
||||
{
|
||||
"origin": "example.com",
|
||||
"resourceRecords": [
|
||||
"stid": "20251121-appf4923-126284",
|
||||
"messages": [
|
||||
{
|
||||
"name": "example.com",
|
||||
"ttl": 120,
|
||||
"type": "TXT",
|
||||
"value": "txt",
|
||||
"pref": 1
|
||||
"text": "string",
|
||||
"notice": "string",
|
||||
"messages": [
|
||||
"string"
|
||||
],
|
||||
"objects": [
|
||||
{
|
||||
"type": "string",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"code": "string",
|
||||
"status": "SUCCESS"
|
||||
}
|
||||
],
|
||||
"action": "xxx",
|
||||
"virtualNameServer": "yyy"
|
||||
"status": {
|
||||
"code": "S0301",
|
||||
"text": "Zone was updated successfully on the name server.",
|
||||
"type": "SUCCESS"
|
||||
},
|
||||
"data": [
|
||||
{
|
||||
"origin": "example.com",
|
||||
"resourceRecords": [
|
||||
{
|
||||
"name": "example.com",
|
||||
"ttl": 120,
|
||||
"type": "TXT",
|
||||
"value": "txt",
|
||||
"pref": 1
|
||||
}
|
||||
],
|
||||
"action": "xxx",
|
||||
"virtualNameServer": "yyy"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,33 +1,133 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type APIResponse[T any] struct {
|
||||
STID string `json:"stid"`
|
||||
CTID string `json:"ctid"`
|
||||
Messages []ResponseMessage `json:"messages"`
|
||||
Status *ResponseStatus `json:"status"`
|
||||
Object *ResponseObject `json:"object"`
|
||||
Data T `json:"data"`
|
||||
}
|
||||
|
||||
type APIError APIResponse[any]
|
||||
|
||||
func (a *APIError) Error() string {
|
||||
var parts []string
|
||||
|
||||
if a.STID != "" {
|
||||
parts = append(parts, fmt.Sprintf("STID: %s", a.STID))
|
||||
}
|
||||
|
||||
if a.CTID != "" {
|
||||
parts = append(parts, fmt.Sprintf("CTID: %s", a.CTID))
|
||||
}
|
||||
|
||||
if a.Status != nil {
|
||||
parts = append(parts, "status: "+a.Status.String())
|
||||
}
|
||||
|
||||
for _, message := range a.Messages {
|
||||
parts = append(parts, "message: "+message.String())
|
||||
}
|
||||
|
||||
if a.Object != nil {
|
||||
parts = append(parts, "object: "+a.Object.String())
|
||||
}
|
||||
|
||||
return strings.Join(parts, ", ")
|
||||
}
|
||||
|
||||
type DataZoneResponse APIResponse[[]Zone]
|
||||
|
||||
type ResponseMessage struct {
|
||||
Text string `json:"text"`
|
||||
Messages []string `json:"messages"`
|
||||
Objects []string `json:"objects"`
|
||||
Code string `json:"code"`
|
||||
Status string `json:"status"`
|
||||
Text string `json:"text"`
|
||||
Code string `json:"code"`
|
||||
Status string `json:"status"`
|
||||
Messages []string `json:"messages"`
|
||||
Objects []GenericObject `json:"objects"`
|
||||
}
|
||||
|
||||
func (r ResponseMessage) String() string {
|
||||
var parts []string
|
||||
|
||||
if r.Code != "" {
|
||||
parts = append(parts, "code: "+r.Code)
|
||||
}
|
||||
|
||||
if r.Text != "" {
|
||||
parts = append(parts, "text: "+r.Text)
|
||||
}
|
||||
|
||||
if r.Status != "" {
|
||||
parts = append(parts, "status: "+r.Status)
|
||||
}
|
||||
|
||||
if len(r.Messages) > 0 {
|
||||
parts = append(parts, "messages: "+strings.Join(r.Messages, ";"))
|
||||
}
|
||||
|
||||
for _, object := range r.Objects {
|
||||
parts = append(parts, fmt.Sprintf("object: %s", object))
|
||||
}
|
||||
|
||||
return strings.Join(parts, ", ")
|
||||
}
|
||||
|
||||
type GenericObject struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func (g GenericObject) String() string {
|
||||
return g.Type + ": " + g.Value
|
||||
}
|
||||
|
||||
type ResponseStatus struct {
|
||||
Code string `json:"code"`
|
||||
Text string `json:"text"`
|
||||
Type string `json:"type"`
|
||||
Type string `json:"type"` // SUCCESS, ERROR, NOTIFY, NOTICE, NICCOM_NOTIFY
|
||||
}
|
||||
|
||||
func (r ResponseStatus) String() string {
|
||||
return fmt.Sprintf("code: %s, text: %s, type: %s", r.Code, r.Text, r.Type)
|
||||
}
|
||||
|
||||
type ResponseObject struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
Summary int32 `json:"summary"`
|
||||
Data string
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
Summary int32 `json:"summary"`
|
||||
Data *ResponseObjectData `json:"data"`
|
||||
}
|
||||
|
||||
type DataZoneResponse struct {
|
||||
STID string `json:"stid"`
|
||||
CTID string `json:"ctid"`
|
||||
Messages []*ResponseMessage `json:"messages"`
|
||||
Status *ResponseStatus `json:"status"`
|
||||
Object any `json:"object"`
|
||||
Data []*Zone `json:"data"`
|
||||
func (r ResponseObject) String() string {
|
||||
var parts []string
|
||||
|
||||
if r.Type != "" {
|
||||
parts = append(parts, fmt.Sprintf("type: %s", r.Type))
|
||||
}
|
||||
|
||||
if r.Value != "" {
|
||||
parts = append(parts, fmt.Sprintf("value: %s", r.Value))
|
||||
}
|
||||
|
||||
if r.Summary != 0 {
|
||||
parts = append(parts, fmt.Sprintf("summary: %d", r.Summary))
|
||||
}
|
||||
|
||||
if r.Data != nil {
|
||||
parts = append(parts, fmt.Sprintf("data: %s", r.Data.Description))
|
||||
}
|
||||
|
||||
return strings.Join(parts, ", ")
|
||||
}
|
||||
|
||||
type ResponseObjectData struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// ResourceRecord holds a resource record.
|
||||
@@ -43,10 +143,10 @@ type ResourceRecord struct {
|
||||
// Zone is an autodns zone record with all for us relevant fields.
|
||||
// https://help.internetx.com/display/APIXMLEN/Zone+Object
|
||||
type Zone struct {
|
||||
Name string `json:"origin"`
|
||||
ResourceRecords []*ResourceRecord `json:"resourceRecords"`
|
||||
Action string `json:"action"`
|
||||
VirtualNameServer string `json:"virtualNameServer"`
|
||||
Name string `json:"origin"`
|
||||
ResourceRecords []ResourceRecord `json:"resourceRecords"`
|
||||
Action string `json:"action"`
|
||||
VirtualNameServer string `json:"virtualNameServer"`
|
||||
}
|
||||
|
||||
// ZoneStream body of the requests.
|
||||
|
||||
Reference in New Issue
Block a user