From b16da88eb70006ca32e1fd62a583fa53bed31890 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Sun, 16 Feb 2025 16:12:47 +0100 Subject: [PATCH] acme-dns: allow the HTTP storage server to create the CNAME (#2437) --- providers/dns/acmedns/acmedns.go | 12 +++++++++++- providers/dns/acmedns/internal/http_storage.go | 8 ++++++++ .../dns/acmedns/internal/http_storage_test.go | 15 +++++++++++++++ providers/dns/acmedns/internal/readme.md | 4 +++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/providers/dns/acmedns/acmedns.go b/providers/dns/acmedns/acmedns.go index 8aabaa14c..9dd63d0a2 100644 --- a/providers/dns/acmedns/acmedns.go +++ b/providers/dns/acmedns/acmedns.go @@ -178,16 +178,26 @@ func (d *DNSProvider) register(ctx context.Context, domain, fqdn string) error { return err } + var cnameCreated bool + // Store the new account in the storage and call save to persist the data. err = d.storage.Put(ctx, domain, newAcct) if err != nil { - return err + cnameCreated = errors.Is(err, internal.ErrCNAMEAlreadyCreated) + if !cnameCreated { + return err + } } + err = d.storage.Save(ctx) if err != nil { return err } + if cnameCreated { + return nil + } + // Stop issuance by returning an error. // The user needs to perform a manual one-time CNAME setup in their DNS zone // to complete the setup of the new account we created. diff --git a/providers/dns/acmedns/internal/http_storage.go b/providers/dns/acmedns/internal/http_storage.go index 1a1e8e2ee..7a535eb20 100644 --- a/providers/dns/acmedns/internal/http_storage.go +++ b/providers/dns/acmedns/internal/http_storage.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -17,6 +18,8 @@ import ( var _ goacmedns.Storage = (*HTTPStorage)(nil) +var ErrCNAMEAlreadyCreated = errors.New("the CNAME has already been created") + // HTTPStorage is an implementation of [acmedns.Storage] over HTTP. type HTTPStorage struct { client *http.Client @@ -98,6 +101,11 @@ func (s *HTTPStorage) do(req *http.Request, result any) error { } if result == nil { + // Hack related to `Put`. + if resp.StatusCode == http.StatusCreated { + return ErrCNAMEAlreadyCreated + } + return nil } diff --git a/providers/dns/acmedns/internal/http_storage_test.go b/providers/dns/acmedns/internal/http_storage_test.go index a628f9a6d..7f9367722 100644 --- a/providers/dns/acmedns/internal/http_storage_test.go +++ b/providers/dns/acmedns/internal/http_storage_test.go @@ -137,3 +137,18 @@ func TestHTTPStorage_Put_error(t *testing.T) { err := storage.Put(context.Background(), "example.com", account) require.Error(t, err) } + +func TestHTTPStorage_Put_CNAME_created(t *testing.T) { + storage := setupTest(t, "POST /example.com", "", http.StatusCreated) + + account := goacmedns.Account{ + FullDomain: "foo.example.com", + SubDomain: "foo", + Username: "user", + Password: "secret", + ServerURL: "https://example.com", + } + + err := storage.Put(context.Background(), "example.com", account) + require.ErrorIs(t, err, ErrCNAMEAlreadyCreated) +} diff --git a/providers/dns/acmedns/internal/readme.md b/providers/dns/acmedns/internal/readme.md index bccdc5388..b667d3d23 100644 --- a/providers/dns/acmedns/internal/readme.md +++ b/providers/dns/acmedns/internal/readme.md @@ -61,7 +61,9 @@ Endpoint: `POST /` ### Response -Response status code 200. +Response status code: +- 200: the process will be stopped to allow the user to create the CNAME. +- 201: the process will continue without error (the CNAME should be created by the server) No expected body.