From ea97ce2f62d340f9261cbd003f742fdf5fcc4470 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 1 Dec 2025 20:51:43 +0100 Subject: [PATCH] chore: move provider "manual" into a dedicated package (#2739) --- .golangci.yml | 4 + challenge/dns01/dns_challenge_manual.go | 5 + cmd/zz_gen_cmd_dnshelp.go | 14 ++- docs/content/dns/zz_gen_manual.md | 98 +++++++++++++++++++ internal/dns/docs/generator.go | 11 +-- internal/dns/docs/templates/dns.go.tmpl | 3 - internal/dns/providers/dns_providers.go.tmpl | 3 - providers/dns/manual/manual.go | 13 +++ .../dns/manual/manual.toml | 23 ++--- .../dns/manual/manual_test.go | 12 +-- providers/dns/zz_gen_dns_providers.go | 6 +- 11 files changed, 149 insertions(+), 43 deletions(-) create mode 100644 docs/content/dns/zz_gen_manual.md create mode 100644 providers/dns/manual/manual.go rename docs/content/dns/manual.md => providers/dns/manual/manual.toml (91%) rename challenge/dns01/dns_challenge_manual_test.go => providers/dns/manual/manual_test.go (73%) diff --git a/.golangci.yml b/.golangci.yml index 2b4bcc41b..ceb7cad85 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -263,6 +263,10 @@ linters: text: cyclomatic complexity 13 of func `\(\*DNSProvider\)\.CleanUp` is high linters: - gocyclo + - path: providers/dns/manual/manual.go + text: 'SA1019: dns01.DNSProviderManual is deprecated' + linters: + - staticcheck # Those elements have been replaced by non-exposed structures. - path: providers/dns/linode/linode_test.go text: 'SA1019: linodego\.(DomainsPagedResponse|DomainRecordsPagedResponse) is deprecated' diff --git a/challenge/dns01/dns_challenge_manual.go b/challenge/dns01/dns_challenge_manual.go index c00d64041..3821fc157 100644 --- a/challenge/dns01/dns_challenge_manual.go +++ b/challenge/dns01/dns_challenge_manual.go @@ -12,9 +12,14 @@ const ( ) // DNSProviderManual is an implementation of the ChallengeProvider interface. +// TODO(ldez): move this to providers/dns/manual +// +// Deprecated: Use the manual.DNSProvider instead. type DNSProviderManual struct{} // NewDNSProviderManual returns a DNSProviderManual instance. +// +// Deprecated: Use the manual.NewDNSProvider instead. func NewDNSProviderManual() (*DNSProviderManual, error) { return &DNSProviderManual{}, nil } diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go index 11cf01280..022374d7a 100644 --- a/cmd/zz_gen_cmd_dnshelp.go +++ b/cmd/zz_gen_cmd_dnshelp.go @@ -12,7 +12,6 @@ import ( func allDNSCodes() string { providers := []string{ - "manual", "acme-dns", "active24", "alidns", @@ -110,6 +109,7 @@ func allDNSCodes() string { "luadns", "mailinabox", "manageengine", + "manual", "metaname", "metaregistrar", "mijnhost", @@ -2270,6 +2270,16 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/manageengine`) + case "manual": + // generated from: providers/dns/manual/manual.toml + ew.writeln(`Configuration for Manual.`) + ew.writeln(`Code: 'manual'`) + ew.writeln(`Since: 'v0.3.0'`) + ew.writeln() + + ew.writeln() + ew.writeln(`More information: https://go-acme.github.io/lego/dns/manual`) + case "metaname": // generated from: providers/dns/metaname/metaname.toml ew.writeln(`Configuration for Metaname.`) @@ -3828,8 +3838,6 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/zonomi`) - case "manual": - ew.writeln(`Solving the DNS-01 challenge using CLI prompt.`) default: return fmt.Errorf("%q is not yet supported", name) } diff --git a/docs/content/dns/zz_gen_manual.md b/docs/content/dns/zz_gen_manual.md new file mode 100644 index 000000000..0300d8400 --- /dev/null +++ b/docs/content/dns/zz_gen_manual.md @@ -0,0 +1,98 @@ +--- +title: "Manual" +date: 2019-03-03T16:39:46+01:00 +draft: false +slug: manual +dnsprovider: + since: "v0.3.0" + code: "manual" + url: "" +--- + + + + + +Solving the DNS-01 challenge using CLI prompt. + + + + +- Code: `manual` +- Since: v0.3.0 + + +Here is an example bash command using the Manual provider: + +```bash +lego --email you@example.com --dns manual -d '*.example.com' -d example.com run +``` + + + + +## Example + +To start using the CLI prompt "provider", start lego with `--dns manual`: + +```console +$ lego --email "you@example.com" --domains="example.com" --dns "manual" run +``` + +What follows are a few log print-outs, interspersed with some prompts, asking for you to do perform some actions: + +```txt +No key found for account you@example.com. Generating a P256 key. +Saved key to ./.lego/accounts/acme-v02.api.letsencrypt.org/you@example.com/keys/you@example.com.key +Please review the TOS at https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf +Do you accept the TOS? Y/n +``` + +If you accept the linked Terms of Service, hit `Enter`. + +```txt +[INFO] acme: Registering account for you@example.com +!!!! HEADS UP !!!! + + Your account credentials have been saved in your Let's Encrypt + configuration directory at "./.lego/accounts". + + You should make a secure backup of this folder now. This + configuration directory will also contain certificates and + private keys obtained from Let's Encrypt so making regular + backups of this folder is ideal. +[INFO] [example.com] acme: Obtaining bundled SAN certificate +[INFO] [example.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/2345678901 +[INFO] [example.com] acme: Could not find solver for: tls-alpn-01 +[INFO] [example.com] acme: Could not find solver for: http-01 +[INFO] [example.com] acme: use dns-01 solver +[INFO] [example.com] acme: Preparing to solve DNS-01 +lego: Please create the following TXT record in your example.com. zone: +_acme-challenge.example.com. 120 IN TXT "hX0dPkG6Gfs9hUvBAchQclkyyoEKbShbpvJ9mY5q2JQ" +lego: Press 'Enter' when you are done +``` + +Do as instructed, and create the TXT records, and hit `Enter`. + +```txt +[INFO] [example.com] acme: Trying to solve DNS-01 +[INFO] [example.com] acme: Checking DNS record propagation using [192.168.8.1:53] +[INFO] Wait for propagation [timeout: 1m0s, interval: 2s] +[INFO] [example.com] acme: Waiting for DNS record propagation. +[INFO] [example.com] The server validated our request +[INFO] [example.com] acme: Cleaning DNS-01 challenge +lego: You can now remove this TXT record from your example.com. zone: +_acme-challenge.example.com. 120 IN TXT "hX0dPkG6Gfs9hUvBAchQclkyyoEKbShbpvJ9mY5q2JQ" +[INFO] [example.com] acme: Validations succeeded; requesting certificates +[INFO] [example.com] Server responded with a certificate. +``` + +As mentioned, you can now remove the TXT record again. + + + + + + + + diff --git a/internal/dns/docs/generator.go b/internal/dns/docs/generator.go index c7f9ef8c7..9355d0d1b 100644 --- a/internal/dns/docs/generator.go +++ b/internal/dns/docs/generator.go @@ -190,14 +190,9 @@ func generateReadMe(models *descriptors.Providers) error { } func orderProviders(models *descriptors.Providers) [][]descriptors.Provider { - providers := append(models.Providers, descriptors.Provider{ - Name: "Manual", - Code: "manual", - }) - const nbCol = 4 - slices.SortFunc(providers, func(a, b descriptors.Provider) int { + slices.SortFunc(models.Providers, func(a, b descriptors.Provider) int { return strings.Compare(strings.ToLower(a.Name), strings.ToLower(b.Name)) }) @@ -206,13 +201,13 @@ func orderProviders(models *descriptors.Providers) [][]descriptors.Provider { row []descriptors.Provider ) - for i, p := range providers { + for i, p := range models.Providers { switch { case len(row) == nbCol: matrix = append(matrix, row) row = []descriptors.Provider{p} - case i == len(providers)-1: + case i == len(models.Providers)-1: row = append(row, p) for j := len(row); j < nbCol; j++ { row = append(row, descriptors.Provider{}) diff --git a/internal/dns/docs/templates/dns.go.tmpl b/internal/dns/docs/templates/dns.go.tmpl index e8b336254..c1896c91a 100644 --- a/internal/dns/docs/templates/dns.go.tmpl +++ b/internal/dns/docs/templates/dns.go.tmpl @@ -12,7 +12,6 @@ import ( func allDNSCodes() string { providers := []string{ - "manual", {{- range $provider := .Providers }} "{{ $provider.Code }}", {{- end}} @@ -48,8 +47,6 @@ func displayDNSHelp(w io.Writer, name string) error { ew.writeln() ew.writeln(`More information: https://go-acme.github.io/lego/dns/{{ $provider.Code }}`) {{end}} - case "manual": - ew.writeln(`Solving the DNS-01 challenge using CLI prompt.`) default: return fmt.Errorf("%q is not yet supported", name) } diff --git a/internal/dns/providers/dns_providers.go.tmpl b/internal/dns/providers/dns_providers.go.tmpl index 2030a3ed0..c974ef6a9 100644 --- a/internal/dns/providers/dns_providers.go.tmpl +++ b/internal/dns/providers/dns_providers.go.tmpl @@ -6,7 +6,6 @@ import ( "fmt" "github.com/go-acme/lego/v4/challenge" - "github.com/go-acme/lego/v4/challenge/dns01" {{- range $provider := .Providers }} "github.com/go-acme/lego/v4/providers/dns/{{ cleanName $provider.Code }}" {{- end}} @@ -15,8 +14,6 @@ import ( // NewDNSChallengeProviderByName Factory for DNS providers. func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) { switch name { - case "manual": - return dns01.NewDNSProviderManual() {{- range $provider := .Providers }} case "{{ $provider.Code }}"{{range $alias := $provider.Aliases }},"{{ $alias }}"{{end}}: return {{ cleanName $provider.Code }}.NewDNSProvider() diff --git a/providers/dns/manual/manual.go b/providers/dns/manual/manual.go new file mode 100644 index 000000000..2985bc595 --- /dev/null +++ b/providers/dns/manual/manual.go @@ -0,0 +1,13 @@ +package manual + +import ( + "github.com/go-acme/lego/v4/challenge/dns01" +) + +// DNSProvider is an implementation of the ChallengeProvider interface. +type DNSProvider = dns01.DNSProviderManual + +// NewDNSProvider returns a DNSProvider instance. +func NewDNSProvider() (*DNSProvider, error) { + return &DNSProvider{}, nil +} diff --git a/docs/content/dns/manual.md b/providers/dns/manual/manual.toml similarity index 91% rename from docs/content/dns/manual.md rename to providers/dns/manual/manual.toml index 3f9cf0a8e..88acf4750 100644 --- a/docs/content/dns/manual.md +++ b/providers/dns/manual/manual.toml @@ -1,18 +1,13 @@ ---- -title: "Manual" -date: 2019-03-03T16:39:46+01:00 -draft: false -slug: manual -dnsprovider: - since: v0.3.0 - code: manual - url: ---- +Name = "Manual" +Description = '''Solving the DNS-01 challenge using CLI prompt.''' +Code = "manual" +Since = "v0.3.0" -Solving the DNS-01 challenge using CLI prompt. - - +Example = ''' +lego --email you@example.com --dns manual -d '*.example.com' -d example.com run +''' +Additional = ''' ## Example To start using the CLI prompt "provider", start lego with `--dns manual`: @@ -70,3 +65,5 @@ _acme-challenge.example.com. 120 IN TXT "hX0dPkG6Gfs9hUvBAchQclkyyoEKbShbpvJ9mY5 ``` As mentioned, you can now remove the TXT record again. + +''' diff --git a/challenge/dns01/dns_challenge_manual_test.go b/providers/dns/manual/manual_test.go similarity index 73% rename from challenge/dns01/dns_challenge_manual_test.go rename to providers/dns/manual/manual_test.go index c183822bb..7badd4b8b 100644 --- a/challenge/dns01/dns_challenge_manual_test.go +++ b/providers/dns/manual/manual_test.go @@ -1,22 +1,14 @@ -package dns01 +package manual import ( "io" "os" "testing" - "github.com/go-acme/lego/v4/platform/tester/dnsmock" - "github.com/miekg/dns" "github.com/stretchr/testify/require" ) func TestDNSProviderManual(t *testing.T) { - useAsNameserver(t, dnsmock.NewServer(). - Query("_acme-challenge.example.com. CNAME", dnsmock.Noop). - Query("_acme-challenge.example.com. SOA", dnsmock.Error(dns.RcodeNameError)). - Query("example.com. SOA", dnsmock.SOA("")). - Build(t)) - backupStdin := os.Stdin defer func() { os.Stdin = backupStdin }() @@ -52,7 +44,7 @@ func TestDNSProviderManual(t *testing.T) { os.Stdin = file - manualProvider, err := NewDNSProviderManual() + manualProvider, err := NewDNSProvider() require.NoError(t, err) err = manualProvider.Present("example.com", "", "") diff --git a/providers/dns/zz_gen_dns_providers.go b/providers/dns/zz_gen_dns_providers.go index 2add1f75f..842d00c51 100644 --- a/providers/dns/zz_gen_dns_providers.go +++ b/providers/dns/zz_gen_dns_providers.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/go-acme/lego/v4/challenge" - "github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/providers/dns/acmedns" "github.com/go-acme/lego/v4/providers/dns/active24" "github.com/go-acme/lego/v4/providers/dns/alidns" @@ -104,6 +103,7 @@ import ( "github.com/go-acme/lego/v4/providers/dns/luadns" "github.com/go-acme/lego/v4/providers/dns/mailinabox" "github.com/go-acme/lego/v4/providers/dns/manageengine" + "github.com/go-acme/lego/v4/providers/dns/manual" "github.com/go-acme/lego/v4/providers/dns/metaname" "github.com/go-acme/lego/v4/providers/dns/metaregistrar" "github.com/go-acme/lego/v4/providers/dns/mijnhost" @@ -181,8 +181,6 @@ import ( // NewDNSChallengeProviderByName Factory for DNS providers. func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) { switch name { - case "manual": - return dns01.NewDNSProviderManual() case "acme-dns", "acmedns": return acmedns.NewDNSProvider() case "active24": @@ -377,6 +375,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) { return mailinabox.NewDNSProvider() case "manageengine": return manageengine.NewDNSProvider() + case "manual": + return manual.NewDNSProvider() case "metaname": return metaname.NewDNSProvider() case "metaregistrar":